[9411] More SpellEffectIndex using in apropriate cases
[getmangos.git] / src / game / BattleGroundMgr.cpp
blob352b145403f93ea9fca4270cc594c52cb3bf4e66
1 /*
2 * Copyright (C) 2005-2010 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_BRACKETS; ++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_BRACKETS; ++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 or player (grp == NULL) to bg queue with the given leader and bg specifications
151 GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, Group* grp, BattleGroundTypeId BgTypeId, PvPDifficultyEntry const* backetEntry, uint8 ArenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 arenateamid)
153 BattleGroundBracketId bracketId = backetEntry->GetBracketId();
155 // create new ginfo
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, bracket_id : %u, index : %u", BgTypeId, bracketId, index);
178 uint32 lastOnlineTime = getMSTime();
180 //announce world (this don't need mutex)
181 if (isRated && sWorld.getConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_ENABLE))
183 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
186 //add players from group to ginfo
188 //ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock);
189 if (grp)
191 for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
193 Player *member = itr->getSource();
194 if(!member)
195 continue; // this should never happen
196 PlayerQueueInfo& pl_info = m_QueuedPlayers[member->GetGUID()];
197 pl_info.LastOnlineTime = lastOnlineTime;
198 pl_info.GroupInfo = ginfo;
199 // add the pinfo to ginfo's list
200 ginfo->Players[member->GetGUID()] = &pl_info;
203 else
205 PlayerQueueInfo& pl_info = m_QueuedPlayers[leader->GetGUID()];
206 pl_info.LastOnlineTime = lastOnlineTime;
207 pl_info.GroupInfo = ginfo;
208 ginfo->Players[leader->GetGUID()] = &pl_info;
211 //add GroupInfo to m_QueuedGroups
212 m_QueuedGroups[bracketId][index].push_back(ginfo);
214 //announce to world, this code needs mutex
215 if (!isRated && !isPremade && sWorld.getConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
217 if (BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId))
219 char const* bgName = bg->GetName();
220 uint32 MinPlayers = bg->GetMinPlayersPerTeam();
221 uint32 qHorde = 0;
222 uint32 qAlliance = 0;
223 uint32 q_min_level = backetEntry->minLevel;
224 uint32 q_max_level = backetEntry->maxLevel;
225 GroupsQueueType::const_iterator itr;
226 for(itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
227 if (!(*itr)->IsInvitedToBGInstanceGUID)
228 qAlliance += (*itr)->Players.size();
229 for(itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
230 if (!(*itr)->IsInvitedToBGInstanceGUID)
231 qHorde += (*itr)->Players.size();
233 // Show queue status to player only (when joining queue)
234 if (sWorld.getConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
236 ChatHandler(leader).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bgName, q_min_level, q_max_level,
237 qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
239 // System message
240 else
242 sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level,
243 qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
247 //release mutex
250 return ginfo;
253 void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BattleGroundBracketId bracket_id)
255 uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, getMSTime());
256 uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
257 if (!ginfo->ArenaType)
259 if (ginfo->Team == HORDE)
260 team_index = BG_TEAM_HORDE;
262 else
264 if (ginfo->IsRated)
265 team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
268 //store pointer to arrayindex of player that was added first
269 uint32* lastPlayerAddedPointer = &(m_WaitTimeLastPlayer[team_index][bracket_id]);
270 //remove his time from sum
271 m_SumOfWaitTimes[team_index][bracket_id] -= m_WaitTimes[team_index][bracket_id][(*lastPlayerAddedPointer)];
272 //set average time to new
273 m_WaitTimes[team_index][bracket_id][(*lastPlayerAddedPointer)] = timeInQueue;
274 //add new time to sum
275 m_SumOfWaitTimes[team_index][bracket_id] += timeInQueue;
276 //set index of last player added to next one
277 (*lastPlayerAddedPointer)++;
278 (*lastPlayerAddedPointer) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME;
281 uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BattleGroundBracketId bracket_id)
283 uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
284 if (!ginfo->ArenaType)
286 if (ginfo->Team == HORDE)
287 team_index = BG_TEAM_HORDE;
289 else
291 if (ginfo->IsRated)
292 team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
294 //check if there is enought values(we always add values > 0)
295 if (m_WaitTimes[team_index][bracket_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] )
296 return (m_SumOfWaitTimes[team_index][bracket_id] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME);
297 else
298 //if there aren't enough values return 0 - not available
299 return 0;
302 //remove player from queue and from group info, if group info is empty then remove it too
303 void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
305 //Player *plr = sObjectMgr.GetPlayer(guid);
306 //ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock);
308 int32 bracket_id = -1; // signed for proper for-loop finish
309 QueuedPlayersMap::iterator itr;
311 //remove player from map, if he's there
312 itr = m_QueuedPlayers.find(guid);
313 if (itr == m_QueuedPlayers.end())
315 sLog.outError("BattleGroundQueue: couldn't find player to remove GUID: %u", GUID_LOPART(guid));
316 return;
319 GroupQueueInfo* group = itr->second.GroupInfo;
320 GroupsQueueType::iterator group_itr, group_itr_tmp;
321 // mostly people with the highest levels are in battlegrounds, thats why
322 // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0
323 // variable index removes useless searching in other team's queue
324 uint32 index = (group->Team == HORDE) ? BG_TEAM_HORDE : BG_TEAM_ALLIANCE;
326 for (int32 bracket_id_tmp = MAX_BATTLEGROUND_BRACKETS - 1; bracket_id_tmp >= 0 && bracket_id == -1; --bracket_id_tmp)
328 //we must check premade and normal team's queue - because when players from premade are joining bg,
329 //they leave groupinfo so we can't use its players size to find out index
330 for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_QUEUE_NORMAL_ALLIANCE)
332 for(group_itr_tmp = m_QueuedGroups[bracket_id_tmp][j].begin(); group_itr_tmp != m_QueuedGroups[bracket_id_tmp][j].end(); ++group_itr_tmp)
334 if ((*group_itr_tmp) == group)
336 bracket_id = bracket_id_tmp;
337 group_itr = group_itr_tmp;
338 //we must store index to be able to erase iterator
339 index = j;
340 break;
345 //player can't be in queue without group, but just in case
346 if (bracket_id == -1)
348 sLog.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid));
349 return;
351 sLog.outDebug("BattleGroundQueue: Removing player GUID %u, from bracket_id %u", GUID_LOPART(guid), (uint32)bracket_id);
353 // ALL variables are correctly set
354 // We can ignore leveling up in queue - it should not cause crash
355 // remove player from group
356 // if only one player there, remove group
358 // remove player queue info from group queue info
359 std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
360 if (pitr != group->Players.end())
361 group->Players.erase(pitr);
363 // if invited to bg, and should decrease invited count, then do it
364 if (decreaseInvitedCount && group->IsInvitedToBGInstanceGUID)
366 BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID, group->BgTypeId);
367 if (bg)
368 bg->DecreaseInvitedCount(group->Team);
371 // remove player queue info
372 m_QueuedPlayers.erase(itr);
374 // announce to world if arena team left queue for rated match, show only once
375 if (group->ArenaType && group->IsRated && group->Players.empty() && sWorld.getConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_ENABLE))
376 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, group->ArenaType, group->ArenaType, group->ArenaTeamRating);
378 //if player leaves queue and he is invited to rated arena match, then he have to loose
379 if (group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount)
381 ArenaTeam * at = sObjectMgr.GetArenaTeamById(group->ArenaTeamId);
382 if (at)
384 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating);
385 Player *plr = sObjectMgr.GetPlayer(guid);
386 if (plr)
387 at->MemberLost(plr, group->OpponentsTeamRating);
388 else
389 at->OfflineMemberLost(guid, group->OpponentsTeamRating);
390 at->SaveToDB();
394 // remove group queue info if needed
395 if (group->Players.empty())
397 m_QueuedGroups[bracket_id][index].erase(group_itr);
398 delete group;
400 // if group wasn't empty, so it wasn't deleted, and player have left a rated
401 // queue -> everyone from the group should leave too
402 // don't remove recursively if already invited to bg!
403 else if (!group->IsInvitedToBGInstanceGUID && group->IsRated)
405 // remove next player, this is recursive
406 // first send removal information
407 if (Player *plr2 = sObjectMgr.GetPlayer(group->Players.begin()->first))
409 BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
410 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType);
411 uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
412 plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to
413 // queue->removeplayer, it causes bugs
414 WorldPacket data;
415 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
416 plr2->GetSession()->SendPacket(&data);
418 // then actually delete, this may delete the group as well!
419 RemovePlayer(group->Players.begin()->first, decreaseInvitedCount);
423 //returns true when player pl_guid is in queue and is invited to bgInstanceGuid
424 bool BattleGroundQueue::IsPlayerInvited(const uint64& pl_guid, const uint32 bgInstanceGuid, const uint32 removeTime)
426 //ACE_Guard<ACE_Recursive_Thread_Mutex> g(m_Lock);
427 QueuedPlayersMap::const_iterator qItr = m_QueuedPlayers.find(pl_guid);
428 return ( qItr != m_QueuedPlayers.end()
429 && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == bgInstanceGuid
430 && qItr->second.GroupInfo->RemoveInviteTime == removeTime );
433 bool BattleGroundQueue::GetPlayerGroupInfoData(const uint64& guid, GroupQueueInfo* ginfo)
435 //ACE_Guard<ACE_Recursive_Thread_Mutex> g(m_Lock);
436 QueuedPlayersMap::const_iterator qItr = m_QueuedPlayers.find(guid);
437 if (qItr == m_QueuedPlayers.end())
438 return false;
439 *ginfo = *(qItr->second.GroupInfo);
440 return true;
443 bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
445 // set side if needed
446 if (side)
447 ginfo->Team = side;
449 if (!ginfo->IsInvitedToBGInstanceGUID)
451 // not yet invited
452 // set invitation
453 ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
454 BattleGroundTypeId bgTypeId = bg->GetTypeID();
455 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, bg->GetArenaType());
456 BattleGroundBracketId bracket_id = bg->GetBracketId();
458 // set ArenaTeamId for rated matches
459 if (bg->isArena() && bg->isRated())
460 bg->SetArenaTeamIdForTeam(ginfo->Team, ginfo->ArenaTeamId);
462 ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME;
464 // loop through the players
465 for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
467 // get the player
468 Player* plr = sObjectMgr.GetPlayer(itr->first);
469 // if offline, skip him, this should not happen - player is removed from queue when he logs out
470 if (!plr)
471 continue;
473 // invite the player
474 PlayerInvitedToBGUpdateAverageWaitTime(ginfo, bracket_id);
475 //sBattleGroundMgr.InvitePlayer(plr, bg, ginfo->Team);
477 // set invited player counters
478 bg->IncreaseInvitedCount(ginfo->Team);
480 plr->SetInviteForBattleGroundQueueType(bgQueueTypeId, ginfo->IsInvitedToBGInstanceGUID);
482 // create remind invite events
483 BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->ArenaType, ginfo->RemoveInviteTime);
484 plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME));
485 // create automatic remove events
486 BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, bgQueueTypeId, ginfo->RemoveInviteTime);
487 plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
489 WorldPacket data;
491 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
493 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());
495 // send status packet
496 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType);
497 plr->GetSession()->SendPacket(&data);
499 return true;
502 return false;
506 This function is inviting players to already running battlegrounds
507 Invitation type is based on config file
508 large groups are disadvantageous, because they will be kicked first if invitation type = 1
510 void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BattleGroundBracketId bracket_id)
512 int32 hordeFree = bg->GetFreeSlotsForTeam(HORDE);
513 int32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE);
515 //iterator for iterating through bg queue
516 GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].begin();
517 //count of groups in queue - used to stop cycles
518 uint32 aliCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].size();
519 //index to queue which group is current
520 uint32 aliIndex = 0;
521 for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++)
522 ++Ali_itr;
523 //the same thing for horde
524 GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].begin();
525 uint32 hordeCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].size();
526 uint32 hordeIndex = 0;
527 for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++)
528 ++Horde_itr;
530 //if ofc like BG queue invitation is set in config, then we are happy
531 if (sWorld.getConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE) == 0)
532 return;
535 if we reached this code, then we have to solve NP - complete problem called Subset sum problem
536 So one solution is to check all possible invitation subgroups, or we can use these conditions:
537 1. Last time when BattleGroundQueue::Update was executed we invited all possible players - so there is only small possibility
538 that we will invite now whole queue, because only 1 change has been made to queues from the last BattleGroundQueue::Update call
539 2. Other thing we should consider is group order in queue
542 // At first we need to compare free space in bg and our selection pool
543 int32 diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
544 int32 diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
545 while( abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0) )
547 //each cycle execution we need to kick at least 1 group
548 if (diffAli < diffHorde)
550 //kick alliance group, add to pool new group if needed
551 if (m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli))
553 for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++)
554 ++Ali_itr;
556 //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break;
557 if (!m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
559 if (aliFree <= diffHorde + 1)
560 break;
561 m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli);
564 else
566 //kick horde group, add to pool new group if needed
567 if (m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde))
569 for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++)
570 ++Horde_itr;
572 if (!m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
574 if (hordeFree <= diffAli + 1)
575 break;
576 m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde);
579 //count diffs after small update
580 diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
581 diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
585 // this method checks if premade versus premade battleground is possible
586 // then after 30 mins (default) in queue it moves premade group to normal queue
587 // it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players
588 bool BattleGroundQueue::CheckPremadeMatch(BattleGroundBracketId bracket_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
590 //check match
591 if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty())
593 //start premade match
594 //if groups aren't invited
595 GroupsQueueType::const_iterator ali_group, horde_group;
596 for( ali_group = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); ali_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++ali_group)
597 if (!(*ali_group)->IsInvitedToBGInstanceGUID)
598 break;
599 for( horde_group = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].begin(); horde_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].end(); ++horde_group)
600 if (!(*horde_group)->IsInvitedToBGInstanceGUID)
601 break;
603 if (ali_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].end())
605 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
606 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
607 //add groups/players from normal queue to size of bigger group
608 uint32 maxPlayers = std::max(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
609 GroupsQueueType::const_iterator itr;
610 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
612 for(itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
614 //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
615 if (!(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers))
616 break;
619 //premade selection pools are set
620 return true;
623 // now check if we can move group from Premade queue to normal queue (timer has expired) or group size lowered!!
624 // this could be 2 cycles but i'm checking only first team in queue - it can cause problem -
625 // 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
626 // and when they click or after 80 seconds the queue info is removed from queue
627 uint32 time_before = getMSTime() - sWorld.getConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
628 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
630 if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
632 GroupsQueueType::iterator itr = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin();
633 if (!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam))
635 //we must insert group to normal queue and erase pointer from premade queue
636 m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
637 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr);
641 //selection pools are not set
642 return false;
645 // this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
646 bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BattleGroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers)
648 GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
649 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
651 itr_team[i] = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
652 for(; itr_team[i] != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i]))
654 if (!(*(itr_team[i]))->IsInvitedToBGInstanceGUID)
656 m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers);
657 if (m_SelectionPools[i].GetPlayerCount() >= minPlayers)
658 break;
662 //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
663 uint32 j = BG_TEAM_ALLIANCE;
664 if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
665 j = BG_TEAM_HORDE;
666 if( sWorld.getConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE) != 0
667 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers )
669 //we will try to invite more groups to team with less players indexed by j
670 ++(itr_team[j]); //this will not cause a crash, because for cycle above reached break;
671 for(; itr_team[j] != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
673 if (!(*(itr_team[j]))->IsInvitedToBGInstanceGUID)
674 if (!m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()))
675 break;
677 // do not allow to start bg with more than 2 players more on 1 faction
678 if (abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2)
679 return false;
681 //allow 1v0 if debug bg
682 if (sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()))
683 return true;
684 //return true if there are enough players in selection pools - enable to work .debug bg command correctly
685 return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers;
688 // this method will check if we can invite players to same faction skirmish match
689 bool BattleGroundQueue::CheckSkirmishForSameFaction(BattleGroundBracketId bracket_id, uint32 minPlayersPerTeam)
691 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam)
692 return false;
693 uint32 teamIndex = BG_TEAM_ALLIANCE;
694 uint32 otherTeam = BG_TEAM_HORDE;
695 uint32 otherTeamId = HORDE;
696 if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam )
698 teamIndex = BG_TEAM_HORDE;
699 otherTeam = BG_TEAM_ALLIANCE;
700 otherTeamId = ALLIANCE;
702 //clear other team's selection
703 m_SelectionPools[otherTeam].Init();
704 //store last ginfo pointer
705 GroupQueueInfo* ginfo = m_SelectionPools[teamIndex].SelectedGroups.back();
706 //set itr_team to group that was added to selection pool latest
707 GroupsQueueType::iterator itr_team = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin();
708 for(; itr_team != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team)
709 if (ginfo == *itr_team)
710 break;
711 if (itr_team == m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end())
712 return false;
713 GroupsQueueType::iterator itr_team2 = itr_team;
714 ++itr_team2;
715 //invite players to other selection pool
716 for(; itr_team2 != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team2)
718 //if selection pool is full then break;
719 if (!(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam))
720 break;
722 if (m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam)
723 return false;
725 //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue
726 for(GroupsQueueType::iterator itr = m_SelectionPools[otherTeam].SelectedGroups.begin(); itr != m_SelectionPools[otherTeam].SelectedGroups.end(); ++itr)
728 //set correct team
729 (*itr)->Team = otherTeamId;
730 //add team to other queue
731 m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + otherTeam].push_front(*itr);
732 //remove team from old queue
733 GroupsQueueType::iterator itr2 = itr_team;
734 ++itr2;
735 for(; itr2 != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2)
737 if (*itr2 == *itr)
739 m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].erase(itr2);
740 break;
744 return true;
748 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
749 it must be called after fully adding the members of a group to ensure group joining
750 should be called from BattleGround::RemovePlayer function in some cases
752 void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketId bracket_id, uint8 arenaType, bool isRated, uint32 arenaRating)
754 //ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock);
755 //if no players in queue - do nothing
756 if( m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
757 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty() &&
758 m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
759 m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].empty() )
760 return;
762 //battleground with free slot for player should be always in the beggining of the queue
763 // maybe it would be better to create bgfreeslotqueue for each bracket_id
764 BGFreeSlotQueueType::iterator itr, next;
765 for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
767 next = itr;
768 ++next;
769 // DO NOT allow queue manager to invite new player to arena
770 if( (*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetBracketId() == bracket_id &&
771 (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE )
773 BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
774 // and iterator is invalid
776 // clear selection pools
777 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
778 m_SelectionPools[BG_TEAM_HORDE].Init();
780 // call a function that does the job for us
781 FillPlayersToBG(bg, bracket_id);
783 // now everything is set, invite players
784 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.end(); ++citr)
785 InviteGroupToBG((*citr), bg, (*citr)->Team);
786 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.end(); ++citr)
787 InviteGroupToBG((*citr), bg, (*citr)->Team);
789 if (!bg->HasFreeSlots())
791 // remove BG from BGFreeSlotQueue
792 bg->RemoveFromBGFreeSlotQueue();
797 // finished iterating through the bgs with free slots, maybe we need to create a new bg
799 BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
800 if (!bg_template)
802 sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
803 return;
806 PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketById(bg_template->GetMapId(),bracket_id);
807 if (!bracketEntry)
809 sLog.outError("Battleground: Update: bg bracket entry not found for map %u bracket id %u", bg_template->GetMapId(), bracket_id);
810 return;
813 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
814 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
815 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
816 if (sBattleGroundMgr.isTesting())
817 MinPlayersPerTeam = 1;
818 if (bg_template->isArena())
820 if (sBattleGroundMgr.isArenaTesting())
822 MaxPlayersPerTeam = 1;
823 MinPlayersPerTeam = 1;
825 else
827 //this switch can be much shorter
828 MaxPlayersPerTeam = arenaType;
829 MinPlayersPerTeam = arenaType;
830 /*switch(arenaType)
832 case ARENA_TYPE_2v2:
833 MaxPlayersPerTeam = 2;
834 MinPlayersPerTeam = 2;
835 break;
836 case ARENA_TYPE_3v3:
837 MaxPlayersPerTeam = 3;
838 MinPlayersPerTeam = 3;
839 break;
840 case ARENA_TYPE_5v5:
841 MaxPlayersPerTeam = 5;
842 MinPlayersPerTeam = 5;
843 break;
848 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
849 m_SelectionPools[BG_TEAM_HORDE].Init();
851 if (bg_template->isBattleGround())
853 //check if there is premade against premade match
854 if (CheckPremadeMatch(bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam))
856 //create new battleground
857 BattleGround * bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, bracketEntry, 0, false);
858 if (!bg2)
860 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
861 return;
863 //invite those selection pools
864 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
865 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
866 InviteGroupToBG((*citr), bg2, (*citr)->Team);
867 //start bg
868 bg2->StartBattleGround();
869 //clear structures
870 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
871 m_SelectionPools[BG_TEAM_HORDE].Init();
875 // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
876 if (!isRated)
878 // if there are enough players in pools, start new battleground or non rated arena
879 if (CheckNormalMatch(bg_template, bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam)
880 || (bg_template->isArena() && CheckSkirmishForSameFaction(bracket_id, MinPlayersPerTeam)) )
882 // we successfully created a pool
883 BattleGround * bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, bracketEntry, arenaType, false);
884 if (!bg2)
886 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
887 return;
890 // invite those selection pools
891 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
892 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
893 InviteGroupToBG((*citr), bg2, (*citr)->Team);
894 // start bg
895 bg2->StartBattleGround();
898 else if (bg_template->isArena())
900 // found out the minimum and maximum ratings the newly added team should battle against
901 // arenaRating is the rating of the latest joined team, or 0
902 // 0 is on (automatic update call) and we must set it to team's with longest wait time
903 if (!arenaRating )
905 GroupQueueInfo* front1 = NULL;
906 GroupQueueInfo* front2 = NULL;
907 if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty())
909 front1 = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].front();
910 arenaRating = front1->ArenaTeamRating;
912 if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty())
914 front2 = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].front();
915 arenaRating = front2->ArenaTeamRating;
917 if (front1 && front2)
919 if (front1->JoinTime < front2->JoinTime)
920 arenaRating = front1->ArenaTeamRating;
922 else if (!front1 && !front2)
923 return; //queues are empty
926 //set rating range
927 uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
928 uint32 arenaMaxRating = arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
929 // if max rating difference is set and the time past since server startup is greater than the rating discard time
930 // (after what time the ratings aren't taken into account when making teams) then
931 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
932 // else leave the discard time on 0, this way all ratings will be discarded
933 uint32 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
935 // we need to find 2 teams which will play next game
937 GroupsQueueType::iterator itr_team[BG_TEAMS_COUNT];
939 //optimalization : --- we dont need to use selection_pools - each update we select max 2 groups
941 for(uint32 i = BG_QUEUE_PREMADE_ALLIANCE; i < BG_QUEUE_NORMAL_ALLIANCE; i++)
943 // take the group that joined first
944 itr_team[i] = m_QueuedGroups[bracket_id][i].begin();
945 for(; itr_team[i] != m_QueuedGroups[bracket_id][i].end(); ++(itr_team[i]))
947 // if group match conditions, then add it to pool
948 if( !(*itr_team[i])->IsInvitedToBGInstanceGUID
949 && (((*itr_team[i])->ArenaTeamRating >= arenaMinRating && (*itr_team[i])->ArenaTeamRating <= arenaMaxRating)
950 || (*itr_team[i])->JoinTime < discardTime) )
952 m_SelectionPools[i].AddGroup((*itr_team[i]), MaxPlayersPerTeam);
953 // break for cycle to be able to start selecting another group from same faction queue
954 break;
958 // now we are done if we have 2 groups - ali vs horde!
959 // if we don't have, we must try to continue search in same queue
960 // tmp variables are correctly set
961 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue
962 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
964 itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE];
965 ++itr_team[BG_TEAM_ALLIANCE];
966 for(; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE]))
968 if( !(*itr_team[BG_TEAM_ALLIANCE])->IsInvitedToBGInstanceGUID
969 && (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
970 || (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime) )
972 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*itr_team[BG_TEAM_ALLIANCE]), MaxPlayersPerTeam);
973 break;
977 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue
978 if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
980 itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE];
981 ++itr_team[BG_TEAM_HORDE];
982 for(; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE]))
984 if( !(*itr_team[BG_TEAM_HORDE])->IsInvitedToBGInstanceGUID
985 && (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating)
986 || (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime) )
988 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*itr_team[BG_TEAM_HORDE]), MaxPlayersPerTeam);
989 break;
994 //if we have 2 teams, then start new arena and invite players!
995 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
997 BattleGround* arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, bracketEntry, arenaType, true);
998 if (!arena)
1000 sLog.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
1001 return;
1004 (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating;
1005 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating);
1006 (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating;
1007 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating);
1008 // 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
1009 if ((*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE)
1011 // add to alliance queue
1012 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE]));
1013 // erase from horde queue
1014 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]);
1015 itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
1017 if ((*(itr_team[BG_TEAM_HORDE]))->Team != HORDE)
1019 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE]));
1020 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]);
1021 itr_team[BG_TEAM_HORDE] = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].begin();
1024 InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE);
1025 InviteGroupToBG(*(itr_team[BG_TEAM_HORDE]), arena, HORDE);
1027 sLog.outDebug("Starting rated arena match!");
1029 arena->StartBattleGround();
1034 /*********************************************************/
1035 /*** BATTLEGROUND QUEUE EVENTS ***/
1036 /*********************************************************/
1038 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1040 Player* plr = sObjectMgr.GetPlayer( m_PlayerGuid );
1041 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1042 if (!plr)
1043 return true;
1045 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1046 //if battleground ended and its instance deleted - do nothing
1047 if (!bg)
1048 return true;
1050 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1051 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1052 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue or in battleground
1054 // check if player is invited to this bg
1055 BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
1056 if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime))
1058 WorldPacket data;
1059 //we must send remaining time in queue
1060 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, m_ArenaType);
1061 plr->GetSession()->SendPacket(&data);
1064 return true; //event will be deleted
1067 void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
1069 //do nothing
1073 this event has many possibilities when it is executed:
1074 1. player is in battleground ( he clicked enter on invitation window )
1075 2. player left battleground queue and he isn't there any more
1076 3. player left battleground queue and he joined it again and IsInvitedToBGInstanceGUID = 0
1077 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
1078 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
1079 we must remove player in the 5. case even if battleground object doesn't exist!
1081 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1083 Player* plr = sObjectMgr.GetPlayer( m_PlayerGuid );
1084 if (!plr)
1085 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1086 return true;
1088 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1089 //battleground can be deleted already when we are removing queue info
1090 //bg pointer can be NULL! so use it carefully!
1092 uint32 queueSlot = plr->GetBattleGroundQueueIndex(m_BgQueueTypeId);
1093 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue, or in Battleground
1095 // check if player is in queue for this BG and if we are removing his invite event
1096 BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId];
1097 if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime))
1099 sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
1101 plr->RemoveBattleGroundQueueId(m_BgQueueTypeId);
1102 bgQueue.RemovePlayer(m_PlayerGuid, true);
1103 //update queues if battleground isn't ended
1104 if (bg && bg->isBattleGround() && bg->GetStatus() != STATUS_WAIT_LEAVE)
1105 sBattleGroundMgr.ScheduleQueueUpdate(0, 0, m_BgQueueTypeId, m_BgTypeId, bg->GetBracketId());
1107 WorldPacket data;
1108 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
1109 plr->GetSession()->SendPacket(&data);
1113 //event will be deleted
1114 return true;
1117 void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
1119 //do nothing
1122 /*********************************************************/
1123 /*** BATTLEGROUND MANAGER ***/
1124 /*********************************************************/
1126 BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
1128 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1129 m_BattleGrounds[i].clear();
1130 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER);
1131 m_Testing=false;
1134 BattleGroundMgr::~BattleGroundMgr()
1136 DeleteAllBattleGrounds();
1139 void BattleGroundMgr::DeleteAllBattleGrounds()
1141 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1143 for(BattleGroundSet::iterator itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end();)
1145 BattleGround * bg = itr->second;
1146 m_BattleGrounds[i].erase(itr++);
1147 if (!m_ClientBattleGroundIds[i][bg->GetBracketId()].empty())
1148 m_ClientBattleGroundIds[i][bg->GetBracketId()].erase(bg->GetClientInstanceID());
1149 delete bg;
1153 // destroy template battlegrounds that listed only in queues (other already terminated)
1154 for(uint32 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId)
1156 // ~BattleGround call unregistring BG from queue
1157 while(!BGFreeSlotQueue[bgTypeId].empty())
1158 delete BGFreeSlotQueue[bgTypeId].front();
1162 // used to update running battlegrounds, and delete finished ones
1163 void BattleGroundMgr::Update(uint32 diff)
1165 BattleGroundSet::iterator itr, next;
1166 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1168 itr = m_BattleGrounds[i].begin();
1169 // skip updating battleground template
1170 if (itr != m_BattleGrounds[i].end())
1171 ++itr;
1172 for(; itr != m_BattleGrounds[i].end(); itr = next)
1174 next = itr;
1175 ++next;
1176 itr->second->Update(diff);
1177 // use the SetDeleteThis variable
1178 // direct deletion caused crashes
1179 if (itr->second->m_SetDeleteThis)
1181 BattleGround * bg = itr->second;
1182 m_BattleGrounds[i].erase(itr);
1183 if (!m_ClientBattleGroundIds[i][bg->GetBracketId()].empty())
1184 m_ClientBattleGroundIds[i][bg->GetBracketId()].erase(bg->GetClientInstanceID());
1185 delete bg;
1190 // update scheduled queues
1191 if (!m_QueueUpdateScheduler.empty())
1193 std::vector<uint64> scheduled;
1195 //create mutex
1196 //ACE_Guard<ACE_Thread_Mutex> guard(SchedulerLock);
1197 //copy vector and clear the other
1198 scheduled = std::vector<uint64>(m_QueueUpdateScheduler);
1199 m_QueueUpdateScheduler.clear();
1200 //release lock
1203 for (uint8 i = 0; i < scheduled.size(); i++)
1205 uint32 arenaRating = scheduled[i] >> 32;
1206 uint8 arenaType = scheduled[i] >> 24 & 255;
1207 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundQueueTypeId(scheduled[i] >> 16 & 255);
1208 BattleGroundTypeId bgTypeId = BattleGroundTypeId((scheduled[i] >> 8) & 255);
1209 BattleGroundBracketId bracket_id = BattleGroundBracketId(scheduled[i] & 255);
1210 m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, bracket_id, arenaType, arenaRating > 0, arenaRating);
1214 // if rating difference counts, maybe force-update queues
1215 if (sWorld.getConfig(CONFIG_UINT32_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER))
1217 // it's time to force update
1218 if (m_NextRatingDiscardUpdate < diff)
1220 // forced update for rated arenas (scan all, but skipped non rated)
1221 sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
1222 for(int qtype = BATTLEGROUND_QUEUE_2v2; qtype <= BATTLEGROUND_QUEUE_5v5; ++qtype)
1223 for(int bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
1224 m_BattleGroundQueues[qtype].Update(
1225 BATTLEGROUND_AA, BattleGroundBracketId(bracket),
1226 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId(qtype)), true, 0);
1228 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER);
1230 else
1231 m_NextRatingDiscardUpdate -= diff;
1233 if (sWorld.getConfig(CONFIG_BOOL_ARENA_AUTO_DISTRIBUTE_POINTS))
1235 if (m_AutoDistributionTimeChecker < diff)
1237 if (sWorld.GetGameTime() > m_NextAutoDistributionTime)
1239 DistributeArenaPoints();
1240 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_UINT32_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1241 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"UI64FMTD"'", uint64(m_NextAutoDistributionTime));
1243 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1245 else
1246 m_AutoDistributionTimeChecker -= diff;
1250 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype)
1252 // we can be in 2 queues in same time...
1254 if (StatusID == 0 || !bg)
1256 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4+8);
1257 *data << uint32(QueueSlot); // queue id (0...1)
1258 *data << uint64(0);
1259 return;
1262 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+8+1+1+4+1+4+4+4));
1263 *data << uint32(QueueSlot); // queue id (0...1) - player can be in 2 queues in time
1264 // uint64 in client
1265 *data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1266 *data << uint8(0); // 3.3.0
1267 *data << uint8(0); // 3.3.0
1268 *data << uint32(bg->GetClientInstanceID());
1269 // alliance/horde for BG and skirmish/rated for Arenas
1270 // following displays the minimap-icon 0 = faction icon 1 = arenaicon
1271 *data << uint8(bg->isRated());
1272 *data << uint32(StatusID); // status
1273 switch(StatusID)
1275 case STATUS_WAIT_QUEUE: // status_in_queue
1276 *data << uint32(Time1); // average wait time, milliseconds
1277 *data << uint32(Time2); // time in queue, updated every minute!, milliseconds
1278 break;
1279 case STATUS_WAIT_JOIN: // status_invite
1280 *data << uint32(bg->GetMapId()); // map id
1281 *data << uint32(Time1); // time to remove from queue, milliseconds
1282 break;
1283 case STATUS_IN_PROGRESS: // status_in_progress
1284 *data << uint32(bg->GetMapId()); // map id
1285 *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
1286 *data << uint32(Time2); // time from bg start, milliseconds
1287 *data << uint8(0x1); // unk sometimes 0x0!
1288 break;
1289 default:
1290 sLog.outError("Unknown BG status!");
1291 break;
1295 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1297 uint8 type = (bg->isArena() ? 1 : 0);
1298 // last check on 3.0.3
1299 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1300 *data << uint8(type); // type (battleground=0/arena=1)
1302 if(type) // arena
1304 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1305 for(int i = 1; i >= 0; --i)
1307 *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
1308 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1309 *data << uint32(0); // added again in 3.1
1310 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1312 for(int i = 1; i >= 0; --i)
1314 uint32 at_id = bg->m_ArenaTeamIds[i];
1315 ArenaTeam * at = sObjectMgr.GetArenaTeamById(at_id);
1316 if (at)
1317 *data << at->GetName();
1318 else
1319 *data << (uint8)0;
1323 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
1325 *data << uint8(0); // bg not ended
1327 else
1329 *data << uint8(1); // bg ended
1330 *data << uint8(bg->GetWinner()); // who win
1333 *data << (int32)(bg->GetPlayerScoresSize());
1335 for(BattleGround::BattleGroundScoreMap::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1337 *data << (uint64)itr->first;
1338 *data << (int32)itr->second->KillingBlows;
1339 if (type == 0)
1341 *data << (int32)itr->second->HonorableKills;
1342 *data << (int32)itr->second->Deaths;
1343 *data << (int32)(itr->second->BonusHonor);
1345 else
1347 Player *plr = sObjectMgr.GetPlayer(itr->first);
1348 uint32 team = bg->GetPlayerTeam(itr->first);
1349 if (!team && plr)
1350 team = plr->GetTeam();
1351 if (( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ))
1352 *data << uint8(1);
1353 else
1354 *data << uint8(0);
1356 *data << (int32)itr->second->DamageDone; // damage done
1357 *data << (int32)itr->second->HealingDone; // healing done
1358 switch(bg->GetTypeID()) // battleground specific things
1360 case BATTLEGROUND_AV:
1361 *data << (uint32)0x00000005; // count of next fields
1362 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1363 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1364 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1365 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1366 *data << (uint32)((BattleGroundAVScore*)itr->second)->SecondaryObjectives; // SecondaryObjectives - free some of the Lieutnants
1367 break;
1368 case BATTLEGROUND_WS:
1369 *data << (uint32)0x00000002; // count of next fields
1370 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1371 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1372 break;
1373 case BATTLEGROUND_AB:
1374 *data << (uint32)0x00000002; // count of next fields
1375 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1376 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1377 break;
1378 case BATTLEGROUND_EY:
1379 *data << (uint32)0x00000001; // count of next fields
1380 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1381 break;
1382 case BATTLEGROUND_NA:
1383 case BATTLEGROUND_BE:
1384 case BATTLEGROUND_AA:
1385 case BATTLEGROUND_RL:
1386 case BATTLEGROUND_SA: // wotlk
1387 case BATTLEGROUND_DS: // wotlk
1388 case BATTLEGROUND_RV: // wotlk
1389 case BATTLEGROUND_IC: // wotlk
1390 case BATTLEGROUND_ABG: // wotlk
1391 *data << (int32)0; // 0
1392 break;
1393 default:
1394 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1395 *data << (int32)0;
1396 break;
1401 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
1403 /*bgTypeId is:
1404 0 - Your group has joined a battleground queue, but you are not eligible
1405 1 - Your group has joined the queue for AV
1406 2 - Your group has joined the queue for WS
1407 3 - Your group has joined the queue for AB
1408 4 - Your group has joined the queue for NA
1409 5 - Your group has joined the queue for BE Arena
1410 6 - Your group has joined the queue for All Arenas
1411 7 - Your group has joined the queue for EotS*/
1412 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1413 *data << uint32(bgTypeId);
1416 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1418 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1419 *data << uint32(field);
1420 *data << uint32(value);
1423 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1425 data->Initialize(SMSG_PLAY_SOUND, 4);
1426 *data << uint32(soundid);
1429 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid)
1431 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1432 *data << uint64(guid);
1435 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1437 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1438 *data << uint64(plr->GetGUID());
1441 BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId)
1443 //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from
1444 //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
1445 BattleGround* bg = GetBattleGroundTemplate(bgTypeId);
1446 if (!bg)
1447 return NULL;
1449 if (bg->isArena())
1450 return GetBattleGround(instanceId, bgTypeId);
1452 for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr)
1454 if (itr->second->GetClientInstanceID() == instanceId)
1455 return itr->second;
1457 return NULL;
1460 BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
1462 //search if needed
1463 BattleGroundSet::iterator itr;
1464 if (bgTypeId == BATTLEGROUND_TYPE_NONE)
1466 for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1468 itr = m_BattleGrounds[i].find(InstanceID);
1469 if (itr != m_BattleGrounds[i].end())
1470 return itr->second;
1472 return NULL;
1474 itr = m_BattleGrounds[bgTypeId].find(InstanceID);
1475 return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL );
1478 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
1480 //map is sorted and we can be sure that lowest instance id has only BG template
1481 return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second;
1484 uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BattleGroundBracketId bracket_id)
1486 if (IsArenaType(bgTypeId))
1487 return 0; //arenas don't have client-instanceids
1489 // we create here an instanceid, which is just for
1490 // displaying this to the client and without any other use..
1491 // the client-instanceIds are unique for each battleground-type
1492 // the instance-id just needs to be as low as possible, beginning with 1
1493 // the following works, because std::set is default ordered with "<"
1494 // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
1495 uint32 lastId = 0;
1496 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][bracket_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][bracket_id].end();)
1498 if( (++lastId) != *itr) //if there is a gap between the ids, we will break..
1499 break;
1500 lastId = *itr;
1502 m_ClientBattleGroundIds[bgTypeId][bracket_id].insert(lastId + 1);
1503 return lastId + 1;
1506 // create a new battleground that will really be used to play
1507 BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated)
1509 // get the template BG
1510 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1511 if (!bg_template)
1513 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1514 return NULL;
1517 //for arenas there is random map used
1518 if (bg_template->isArena())
1520 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
1521 uint32 arena_num = urand(0,2);
1522 bgTypeId = arenas[arena_num];
1523 bg_template = GetBattleGroundTemplate(bgTypeId);
1524 if (!bg_template)
1526 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1527 return NULL;
1531 BattleGround *bg = NULL;
1532 // create a copy of the BG template
1533 switch(bgTypeId)
1535 case BATTLEGROUND_AV:
1536 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1537 break;
1538 case BATTLEGROUND_WS:
1539 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1540 break;
1541 case BATTLEGROUND_AB:
1542 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1543 break;
1544 case BATTLEGROUND_NA:
1545 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1546 break;
1547 case BATTLEGROUND_BE:
1548 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1549 break;
1550 case BATTLEGROUND_AA:
1551 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1552 break;
1553 case BATTLEGROUND_EY:
1554 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1555 break;
1556 case BATTLEGROUND_RL:
1557 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1558 break;
1559 case BATTLEGROUND_SA:
1560 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1561 break;
1562 case BATTLEGROUND_DS:
1563 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1564 break;
1565 case BATTLEGROUND_RV:
1566 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1567 break;
1568 case BATTLEGROUND_IC:
1569 bg = new BattleGroundIC(*(BattleGroundIC*)bg_template);
1570 break;
1571 case BATTLEGROUND_ABG:
1572 bg = new BattleGroundABG(*(BattleGroundABG*)bg_template);
1573 break;
1574 default:
1575 //error, but it is handled few lines above
1576 return 0;
1579 // generate a new instance id
1580 bg->SetInstanceID(sMapMgr.GenerateInstanceId()); // set instance id
1581 bg->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId, bracketEntry->GetBracketId()));
1583 // reset the new bg (set status to status_wait_queue from status_none)
1584 bg->Reset();
1586 // start the joining of the bg
1587 bg->SetStatus(STATUS_WAIT_JOIN);
1588 bg->SetBracket(bracketEntry);
1589 bg->SetArenaType(arenaType);
1590 bg->SetRated(isRated);
1592 return bg;
1595 // used to create the BG templates
1596 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)
1598 // Create the BG
1599 BattleGround *bg = NULL;
1600 switch(bgTypeId)
1602 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1603 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1604 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1605 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1606 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1607 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1608 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1609 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1610 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1611 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1612 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1613 case BATTLEGROUND_IC: bg = new BattleGroundIC; break;
1614 case BATTLEGROUND_ABG: bg = new BattleGroundABG; break;
1615 default:bg = new BattleGround; break; // placeholder for non implemented BG
1618 bg->SetMapId(MapID);
1619 bg->SetTypeID(bgTypeId);
1620 bg->SetInstanceID(0);
1621 bg->SetArenaorBGType(IsArena);
1622 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1623 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1624 bg->SetMinPlayers(MinPlayersPerTeam * 2);
1625 bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
1626 bg->SetName(BattleGroundName);
1627 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1628 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1629 bg->SetLevelRange(LevelMin, LevelMax);
1631 // add bg to update list
1632 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1634 // return some not-null value, bgTypeId is good enough for me
1635 return bgTypeId;
1638 void BattleGroundMgr::CreateInitialBattleGrounds()
1640 float AStartLoc[4];
1641 float HStartLoc[4];
1642 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1643 BattlemasterListEntry const *bl;
1644 WorldSafeLocsEntry const *start;
1645 bool IsArena;
1647 uint32 count = 0;
1649 // 0 1 2 3 4 5 6 7 8
1650 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1652 if (!result)
1654 barGoLink bar(1);
1656 bar.step();
1658 sLog.outString();
1659 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1660 return;
1663 barGoLink bar((int)result->GetRowCount());
1667 Field *fields = result->Fetch();
1668 bar.step();
1670 uint32 bgTypeID_ = fields[0].GetUInt32();
1672 // can be overwrite by values from DB
1673 bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
1674 if (!bl)
1676 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
1677 continue;
1680 BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
1682 IsArena = (bl->type == TYPE_ARENA);
1683 MinPlayersPerTeam = fields[1].GetUInt32();
1684 MaxPlayersPerTeam = fields[2].GetUInt32();
1685 MinLvl = fields[3].GetUInt32();
1686 MaxLvl = fields[4].GetUInt32();
1687 //check values from DB
1688 if (MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam)
1690 MaxPlayersPerTeam = bl->maxplayersperteam;
1691 MinPlayersPerTeam = bl->maxplayersperteam; // by default now expected strong full bg requirement
1693 if (MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl)
1695 // TODO: fix me
1696 MinLvl = 0;//bl->minlvl;
1697 MaxLvl = 80;//bl->maxlvl;
1700 start1 = fields[5].GetUInt32();
1702 start = sWorldSafeLocsStore.LookupEntry(start1);
1703 if (start)
1705 AStartLoc[0] = start->x;
1706 AStartLoc[1] = start->y;
1707 AStartLoc[2] = start->z;
1708 AStartLoc[3] = fields[6].GetFloat();
1710 else if (bgTypeID == BATTLEGROUND_AA || bgTypeID == BATTLEGROUND_ABG)
1712 AStartLoc[0] = 0;
1713 AStartLoc[1] = 0;
1714 AStartLoc[2] = 0;
1715 AStartLoc[3] = fields[6].GetFloat();
1717 else
1719 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
1720 continue;
1723 start2 = fields[7].GetUInt32();
1725 start = sWorldSafeLocsStore.LookupEntry(start2);
1726 if (start)
1728 HStartLoc[0] = start->x;
1729 HStartLoc[1] = start->y;
1730 HStartLoc[2] = start->z;
1731 HStartLoc[3] = fields[8].GetFloat();
1733 else if (bgTypeID == BATTLEGROUND_AA || bgTypeID == BATTLEGROUND_ABG)
1735 HStartLoc[0] = 0;
1736 HStartLoc[1] = 0;
1737 HStartLoc[2] = 0;
1738 HStartLoc[3] = fields[8].GetFloat();
1740 else
1742 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
1743 continue;
1746 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1747 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]))
1748 continue;
1750 ++count;
1751 } while (result->NextRow());
1753 delete result;
1755 sLog.outString();
1756 sLog.outString( ">> Loaded %u battlegrounds", count );
1759 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1761 if (sWorld.getConfig(CONFIG_BOOL_ARENA_AUTO_DISTRIBUTE_POINTS))
1763 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1764 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1765 if (!result)
1767 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1768 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_UINT32_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1769 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"UI64FMTD"')", uint64(m_NextAutoDistributionTime));
1771 else
1773 m_NextAutoDistributionTime = time_t((*result)[0].GetUInt64());
1774 delete result;
1776 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1780 void BattleGroundMgr::DistributeArenaPoints()
1782 // used to distribute arena points based on last week's stats
1783 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
1785 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
1787 //temporary structure for storing maximum points to add values for all players
1788 std::map<uint32, uint32> PlayerPoints;
1790 //at first update all points for all team members
1791 for(ObjectMgr::ArenaTeamMap::iterator team_itr = sObjectMgr.GetArenaTeamMapBegin(); team_itr != sObjectMgr.GetArenaTeamMapEnd(); ++team_itr)
1793 if (ArenaTeam * at = team_itr->second)
1795 at->UpdateArenaPointsHelper(PlayerPoints);
1799 //cycle that gives points to all players
1800 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1802 //update to database
1803 CharacterDatabase.PExecute("UPDATE characters SET arenaPoints = arenaPoints + '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
1804 //add points if player is online
1805 Player* pl = sObjectMgr.GetPlayer(plr_itr->first);
1806 if (pl)
1807 pl->ModifyArenaPoints(plr_itr->second);
1810 PlayerPoints.clear();
1812 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
1814 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
1815 for(ObjectMgr::ArenaTeamMap::iterator titr = sObjectMgr.GetArenaTeamMapBegin(); titr != sObjectMgr.GetArenaTeamMapEnd(); ++titr)
1817 if (ArenaTeam * at = titr->second)
1819 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1820 at->SaveToDB(); // save changes
1821 at->NotifyStatsChanged(); // notify the players of the changes
1825 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
1827 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
1830 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId, uint8 fromWhere)
1832 if (!plr)
1833 return;
1835 data->Initialize(SMSG_BATTLEFIELD_LIST);
1836 *data << uint64(guid); // battlemaster guid
1837 *data << uint8(fromWhere); // from where you joined
1838 *data << uint32(bgTypeId); // battleground id
1839 if(bgTypeId == BATTLEGROUND_AA) // arena
1841 *data << uint8(4); // unk
1842 *data << uint8(0); // unk
1843 *data << uint32(0); // unk (count?)
1845 else // battleground
1847 *data << uint8(0); // unk, different for each bg type
1848 *data << uint8(0); // unk
1850 size_t count_pos = data->wpos();
1851 uint32 count = 0;
1852 *data << uint32(0); // number of bg instances
1854 if(BattleGround* bgTemplate = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId))
1856 // expected bracket entry
1857 if(PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bgTemplate->GetMapId(),plr->getLevel()))
1859 BattleGroundBracketId bracketId = bracketEntry->GetBracketId();
1860 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][bracketId].begin(); itr != m_ClientBattleGroundIds[bgTypeId][bracketId].end();++itr)
1862 *data << uint32(*itr);
1863 ++count;
1865 data->put<uint32>( count_pos , count);
1871 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId)
1873 BattleGround *bg = GetBattleGround(instanceId, bgTypeId);
1874 if (bg)
1876 uint32 mapid = bg->GetMapId();
1877 float x, y, z, O;
1878 uint32 team = pl->GetBGTeam();
1879 if (team==0)
1880 team = pl->GetTeam();
1881 bg->GetTeamStartLoc(team, x, y, z, O);
1883 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1884 pl->TeleportTo(mapid, x, y, z, O);
1886 else
1888 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1892 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
1894 return ( bgTypeId == BATTLEGROUND_AA ||
1895 bgTypeId == BATTLEGROUND_BE ||
1896 bgTypeId == BATTLEGROUND_NA ||
1897 bgTypeId == BATTLEGROUND_RL );
1900 BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
1902 switch(bgTypeId)
1904 case BATTLEGROUND_WS:
1905 return BATTLEGROUND_QUEUE_WS;
1906 case BATTLEGROUND_AB:
1907 return BATTLEGROUND_QUEUE_AB;
1908 case BATTLEGROUND_AV:
1909 return BATTLEGROUND_QUEUE_AV;
1910 case BATTLEGROUND_EY:
1911 return BATTLEGROUND_QUEUE_EY;
1912 case BATTLEGROUND_SA:
1913 return BATTLEGROUND_QUEUE_SA;
1914 case BATTLEGROUND_IC:
1915 return BATTLEGROUND_QUEUE_IC;
1916 case BATTLEGROUND_ABG:
1917 return BATTLEGROUND_QUEUE_NONE;
1918 case BATTLEGROUND_AA:
1919 case BATTLEGROUND_NA:
1920 case BATTLEGROUND_RL:
1921 case BATTLEGROUND_BE:
1922 case BATTLEGROUND_DS:
1923 case BATTLEGROUND_RV:
1924 switch(arenaType)
1926 case ARENA_TYPE_2v2:
1927 return BATTLEGROUND_QUEUE_2v2;
1928 case ARENA_TYPE_3v3:
1929 return BATTLEGROUND_QUEUE_3v3;
1930 case ARENA_TYPE_5v5:
1931 return BATTLEGROUND_QUEUE_5v5;
1932 default:
1933 return BATTLEGROUND_QUEUE_NONE;
1935 default:
1936 return BATTLEGROUND_QUEUE_NONE;
1940 BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId)
1942 switch(bgQueueTypeId)
1944 case BATTLEGROUND_QUEUE_WS:
1945 return BATTLEGROUND_WS;
1946 case BATTLEGROUND_QUEUE_AB:
1947 return BATTLEGROUND_AB;
1948 case BATTLEGROUND_QUEUE_AV:
1949 return BATTLEGROUND_AV;
1950 case BATTLEGROUND_QUEUE_EY:
1951 return BATTLEGROUND_EY;
1952 case BATTLEGROUND_QUEUE_SA:
1953 return BATTLEGROUND_SA;
1954 case BATTLEGROUND_QUEUE_IC:
1955 return BATTLEGROUND_IC;
1956 case BATTLEGROUND_QUEUE_2v2:
1957 case BATTLEGROUND_QUEUE_3v3:
1958 case BATTLEGROUND_QUEUE_5v5:
1959 return BATTLEGROUND_AA;
1960 default:
1961 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
1965 uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId)
1967 switch(bgQueueTypeId)
1969 case BATTLEGROUND_QUEUE_2v2:
1970 return ARENA_TYPE_2v2;
1971 case BATTLEGROUND_QUEUE_3v3:
1972 return ARENA_TYPE_3v3;
1973 case BATTLEGROUND_QUEUE_5v5:
1974 return ARENA_TYPE_5v5;
1975 default:
1976 return 0;
1980 void BattleGroundMgr::ToggleTesting()
1982 m_Testing = !m_Testing;
1983 if (m_Testing)
1984 sWorld.SendWorldText(LANG_DEBUG_BG_ON);
1985 else
1986 sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
1989 void BattleGroundMgr::ToggleArenaTesting()
1991 m_ArenaTesting = !m_ArenaTesting;
1992 if (m_ArenaTesting)
1993 sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
1994 else
1995 sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
1998 void BattleGroundMgr::ScheduleQueueUpdate(uint32 arenaRating, uint8 arenaType, BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BattleGroundBracketId bracket_id)
2000 //ACE_Guard<ACE_Thread_Mutex> guard(SchedulerLock);
2001 //we will use only 1 number created of bgTypeId and bracket_id
2002 uint64 schedule_id = ((uint64)arenaRating << 32) | (arenaType << 24) | (bgQueueTypeId << 16) | (bgTypeId << 8) | bracket_id;
2003 bool found = false;
2004 for (uint8 i = 0; i < m_QueueUpdateScheduler.size(); i++)
2006 if (m_QueueUpdateScheduler[i] == schedule_id)
2008 found = true;
2009 break;
2012 if (!found)
2013 m_QueueUpdateScheduler.push_back(schedule_id);
2016 uint32 BattleGroundMgr::GetMaxRatingDifference() const
2018 // this is for stupid people who can't use brain and set max rating difference to 0
2019 uint32 diff = sWorld.getConfig(CONFIG_UINT32_ARENA_MAX_RATING_DIFFERENCE);
2020 if (diff == 0)
2021 diff = 5000;
2022 return diff;
2025 uint32 BattleGroundMgr::GetRatingDiscardTimer() const
2027 return sWorld.getConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER);
2030 uint32 BattleGroundMgr::GetPrematureFinishTime() const
2032 return sWorld.getConfig(CONFIG_UINT32_BATTLEGROUND_PREMATURE_FINISH_TIMER);
2035 void BattleGroundMgr::LoadBattleMastersEntry()
2037 mBattleMastersMap.clear(); // need for reload case
2039 QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
2041 uint32 count = 0;
2043 if (!result)
2045 barGoLink bar( 1 );
2046 bar.step();
2048 sLog.outString();
2049 sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
2050 return;
2053 barGoLink bar( (int)result->GetRowCount() );
2057 ++count;
2058 bar.step();
2060 Field *fields = result->Fetch();
2062 uint32 entry = fields[0].GetUInt32();
2063 uint32 bgTypeId = fields[1].GetUInt32();
2064 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
2066 sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
2067 continue;
2070 mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
2072 } while( result->NextRow() );
2074 delete result;
2076 sLog.outString();
2077 sLog.outString( ">> Loaded %u battlemaster entries", count );
2080 bool BattleGroundMgr::IsBGWeekend(BattleGroundTypeId bgTypeId)
2082 switch (bgTypeId)
2084 case BATTLEGROUND_AV:
2085 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_AV);
2086 case BATTLEGROUND_EY:
2087 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_EY);
2088 case BATTLEGROUND_WS:
2089 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_WS);
2090 case BATTLEGROUND_SA:
2091 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_SA);
2092 default:
2093 return false;
2097 void BattleGroundMgr::LoadBattleEventIndexes()
2099 BattleGroundEventIdx events;
2100 events.event1 = BG_EVENT_NONE;
2101 events.event2 = BG_EVENT_NONE;
2102 m_GameObjectBattleEventIndexMap.clear(); // need for reload case
2103 m_GameObjectBattleEventIndexMap[-1] = events;
2104 m_CreatureBattleEventIndexMap.clear(); // need for reload case
2105 m_CreatureBattleEventIndexMap[-1] = events;
2107 uint32 count = 0;
2109 QueryResult *result =
2110 // 0 1 2 3 4 5 6
2111 WorldDatabase.PQuery( "SELECT data.typ, data.guid1, data.ev1 AS ev1, data.ev2 AS ev2, data.map AS m, data.guid2, description.map, "
2112 // 7 8 9
2113 "description.event1, description.event2, description.description "
2114 "FROM "
2115 "(SELECT '1' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2116 "FROM gameobject_battleground AS a "
2117 "LEFT OUTER JOIN gameobject AS b ON a.guid = b.guid "
2118 "UNION "
2119 "SELECT '2' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2120 "FROM creature_battleground AS a "
2121 "LEFT OUTER JOIN creature AS b ON a.guid = b.guid "
2122 ") data "
2123 "RIGHT OUTER JOIN battleground_events AS description ON data.map = description.map "
2124 "AND data.ev1 = description.event1 AND data.ev2 = description.event2 "
2125 // full outer join doesn't work in mysql :-/ so just UNION-select the same again and add a left outer join
2126 "UNION "
2127 "SELECT data.typ, data.guid1, data.ev1, data.ev2, data.map, data.guid2, description.map, "
2128 "description.event1, description.event2, description.description "
2129 "FROM "
2130 "(SELECT '1' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2131 "FROM gameobject_battleground AS a "
2132 "LEFT OUTER JOIN gameobject AS b ON a.guid = b.guid "
2133 "UNION "
2134 "SELECT '2' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2135 "FROM creature_battleground AS a "
2136 "LEFT OUTER JOIN creature AS b ON a.guid = b.guid "
2137 ") data "
2138 "LEFT OUTER JOIN battleground_events AS description ON data.map = description.map "
2139 "AND data.ev1 = description.event1 AND data.ev2 = description.event2 "
2140 "ORDER BY m, ev1, ev2" );
2141 if(!result)
2143 barGoLink bar(1);
2144 bar.step();
2146 sLog.outString();
2147 sLog.outErrorDb(">> Loaded 0 battleground eventindexes.");
2148 return;
2151 barGoLink bar((int)result->GetRowCount());
2155 bar.step();
2156 Field *fields = result->Fetch();
2157 if (fields[2].GetUInt8() == BG_EVENT_NONE || fields[3].GetUInt8() == BG_EVENT_NONE)
2158 continue; // we don't need to add those to the eventmap
2160 bool gameobject = (fields[0].GetUInt8() == 1);
2161 uint32 dbTableGuidLow = fields[1].GetUInt32();
2162 events.event1 = fields[2].GetUInt8();
2163 events.event2 = fields[3].GetUInt8();
2164 uint32 map = fields[4].GetUInt32();
2166 uint32 desc_map = fields[6].GetUInt32();
2167 uint8 desc_event1 = fields[7].GetUInt8();
2168 uint8 desc_event2 = fields[8].GetUInt8();
2169 const char *description = fields[9].GetString();
2171 // checking for NULL - through right outer join this will mean following:
2172 if (fields[5].GetUInt32() != dbTableGuidLow)
2174 sLog.outErrorDb("BattleGroundEvent: %s with nonexistant guid %u for event: map:%u, event1:%u, event2:%u (\"%s\")",
2175 (gameobject) ? "gameobject" : "creature", dbTableGuidLow, map, events.event1, events.event2, description);
2176 continue;
2179 // checking for NULL - through full outer join this can mean 2 things:
2180 if (desc_map != map)
2182 // there is an event missing
2183 if (dbTableGuidLow == 0)
2185 sLog.outErrorDb("BattleGroundEvent: missing db-data for map:%u, event1:%u, event2:%u (\"%s\")", desc_map, desc_event1, desc_event2, description);
2186 continue;
2188 // we have an event which shouldn't exist
2189 else
2191 sLog.outErrorDb("BattleGroundEvent: %s with guid %u is registered, for a nonexistant event: map:%u, event1:%u, event2:%u",
2192 (gameobject) ? "gameobject" : "creature", dbTableGuidLow, map, events.event1, events.event2);
2193 continue;
2197 if (gameobject)
2198 m_GameObjectBattleEventIndexMap[dbTableGuidLow] = events;
2199 else
2200 m_CreatureBattleEventIndexMap[dbTableGuidLow] = events;
2202 ++count;
2204 } while(result->NextRow());
2206 sLog.outString();
2207 sLog.outString( ">> Loaded %u battleground eventindexes", count);
2208 delete result;