Merge branch 'master' into 330
[getmangos.git] / src / game / BattleGroundMgr.cpp
blob4c2c02bf556209320d44a4b0933125f8cd39a50d
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_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 or player (grp == NULL) to bg queue with the given leader and bg specifications
151 GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, Group* grp, BattleGroundTypeId BgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 arenateamid)
153 BGQueueIdBasedOnLevel queue_id = leader->GetBattleGroundQueueIdFromLevel();
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, queue_id : %u, index : %u", BgTypeId, queue_id, index);
178 uint32 lastOnlineTime = getMSTime();
180 //announce world (this don't need mutex)
181 if (isRated && sWorld.getConfig(CONFIG_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[queue_id][index].push_back(ginfo);
214 //announce to world, this code needs mutex
215 if (!isRated && !isPremade && sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
217 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
218 if (bg)
220 char const* bgName = bg->GetName();
221 uint32 MinPlayers = bg->GetMinPlayersPerTeam();
222 uint32 qHorde = 0;
223 uint32 qAlliance = 0;
224 uint32 q_min_level = (queue_id + 1) * 10;
225 GroupsQueueType::const_iterator itr;
226 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
227 if (!(*itr)->IsInvitedToBGInstanceGUID)
228 qAlliance += (*itr)->Players.size();
229 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[queue_id][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_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
236 ChatHandler(leader).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bgName, q_min_level, q_min_level + 10,
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_min_level + 10,
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, BGQueueIdBasedOnLevel queue_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][queue_id]);
270 //remove his time from sum
271 m_SumOfWaitTimes[team_index][queue_id] -= m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)];
272 //set average time to new
273 m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)] = timeInQueue;
274 //add new time to sum
275 m_SumOfWaitTimes[team_index][queue_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, BGQueueIdBasedOnLevel queue_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][queue_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] )
296 return (m_SumOfWaitTimes[team_index][queue_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 queue_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 queue_id_tmp = MAX_BATTLEGROUND_QUEUES - 1; queue_id_tmp >= 0 && queue_id == -1; --queue_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[queue_id_tmp][j].begin(); group_itr_tmp != m_QueuedGroups[queue_id_tmp][j].end(); ++group_itr_tmp)
334 if ((*group_itr_tmp) == group)
336 queue_id = queue_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 (queue_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 queue_id %u", GUID_LOPART(guid), (uint32)queue_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_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[queue_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 BGQueueIdBasedOnLevel queue_id = bg->GetQueueId();
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, queue_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, BGQueueIdBasedOnLevel queue_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[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin();
517 //count of groups in queue - used to stop cycles
518 uint32 aliCount = m_QueuedGroups[queue_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[queue_id][BG_QUEUE_NORMAL_HORDE].begin();
525 uint32 hordeCount = m_QueuedGroups[queue_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_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(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
590 //check match
591 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_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[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++ali_group)
597 if (!(*ali_group)->IsInvitedToBGInstanceGUID)
598 break;
599 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)
600 if (!(*horde_group)->IsInvitedToBGInstanceGUID)
601 break;
603 if (ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[queue_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[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[queue_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_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
628 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
630 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
632 GroupsQueueType::iterator itr = m_QueuedGroups[queue_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[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
637 m_QueuedGroups[queue_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, BGQueueIdBasedOnLevel queue_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[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
652 for(; itr_team[i] != m_QueuedGroups[queue_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_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[queue_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(BGQueueIdBasedOnLevel queue_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[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin();
708 for(; itr_team != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team)
709 if (ginfo == *itr_team)
710 break;
711 if (itr_team == m_QueuedGroups[queue_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[queue_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[queue_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[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2)
737 if (*itr2 == *itr)
739 m_QueuedGroups[queue_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, BGQueueIdBasedOnLevel queue_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[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
757 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() &&
758 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
759 m_QueuedGroups[queue_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 queue_id_based_on_level
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)->GetQueueId() == queue_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, queue_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;
805 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
806 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
807 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
808 if (sBattleGroundMgr.isTesting())
809 MinPlayersPerTeam = 1;
810 if (bg_template->isArena())
812 if (sBattleGroundMgr.isArenaTesting())
814 MaxPlayersPerTeam = 1;
815 MinPlayersPerTeam = 1;
817 else
819 //this switch can be much shorter
820 MaxPlayersPerTeam = arenaType;
821 MinPlayersPerTeam = arenaType;
822 /*switch(arenaType)
824 case ARENA_TYPE_2v2:
825 MaxPlayersPerTeam = 2;
826 MinPlayersPerTeam = 2;
827 break;
828 case ARENA_TYPE_3v3:
829 MaxPlayersPerTeam = 3;
830 MinPlayersPerTeam = 3;
831 break;
832 case ARENA_TYPE_5v5:
833 MaxPlayersPerTeam = 5;
834 MinPlayersPerTeam = 5;
835 break;
840 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
841 m_SelectionPools[BG_TEAM_HORDE].Init();
843 if (bg_template->isBattleGround())
845 //check if there is premade against premade match
846 if (CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam))
848 //create new battleground
849 BattleGround * bg2 = NULL;
850 if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, 0, false)))
852 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
853 return;
855 //invite those selection pools
856 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
857 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
858 InviteGroupToBG((*citr), bg2, (*citr)->Team);
859 //start bg
860 bg2->StartBattleGround();
861 //clear structures
862 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
863 m_SelectionPools[BG_TEAM_HORDE].Init();
867 // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
868 if (!isRated)
870 // if there are enough players in pools, start new battleground or non rated arena
871 if (CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam)
872 || (bg_template->isArena() && CheckSkirmishForSameFaction(queue_id, MinPlayersPerTeam)) )
874 // we successfully created a pool
875 BattleGround * bg2 = NULL;
876 if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, false)))
878 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
879 return;
882 // invite those selection pools
883 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
884 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
885 InviteGroupToBG((*citr), bg2, (*citr)->Team);
886 // start bg
887 bg2->StartBattleGround();
890 else if (bg_template->isArena())
892 // found out the minimum and maximum ratings the newly added team should battle against
893 // arenaRating is the rating of the latest joined team, or 0
894 // 0 is on (automatic update call) and we must set it to team's with longest wait time
895 if (!arenaRating )
897 GroupQueueInfo* front1 = NULL;
898 GroupQueueInfo* front2 = NULL;
899 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty())
901 front1 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].front();
902 arenaRating = front1->ArenaTeamRating;
904 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
906 front2 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].front();
907 arenaRating = front2->ArenaTeamRating;
909 if (front1 && front2)
911 if (front1->JoinTime < front2->JoinTime)
912 arenaRating = front1->ArenaTeamRating;
914 else if (!front1 && !front2)
915 return; //queues are empty
918 //set rating range
919 uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
920 uint32 arenaMaxRating = arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
921 // if max rating difference is set and the time past since server startup is greater than the rating discard time
922 // (after what time the ratings aren't taken into account when making teams) then
923 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
924 // else leave the discard time on 0, this way all ratings will be discarded
925 uint32 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
927 // we need to find 2 teams which will play next game
929 GroupsQueueType::iterator itr_team[BG_TEAMS_COUNT];
931 //optimalization : --- we dont need to use selection_pools - each update we select max 2 groups
933 for(uint32 i = BG_QUEUE_PREMADE_ALLIANCE; i < BG_QUEUE_NORMAL_ALLIANCE; i++)
935 // take the group that joined first
936 itr_team[i] = m_QueuedGroups[queue_id][i].begin();
937 for(; itr_team[i] != m_QueuedGroups[queue_id][i].end(); ++(itr_team[i]))
939 // if group match conditions, then add it to pool
940 if( !(*itr_team[i])->IsInvitedToBGInstanceGUID
941 && (((*itr_team[i])->ArenaTeamRating >= arenaMinRating && (*itr_team[i])->ArenaTeamRating <= arenaMaxRating)
942 || (*itr_team[i])->JoinTime < discardTime) )
944 m_SelectionPools[i].AddGroup((*itr_team[i]), MaxPlayersPerTeam);
945 // break for cycle to be able to start selecting another group from same faction queue
946 break;
950 // now we are done if we have 2 groups - ali vs horde!
951 // if we don't have, we must try to continue search in same queue
952 // tmp variables are correctly set
953 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue
954 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
956 itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE];
957 ++itr_team[BG_TEAM_ALLIANCE];
958 for(; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE]))
960 if( !(*itr_team[BG_TEAM_ALLIANCE])->IsInvitedToBGInstanceGUID
961 && (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
962 || (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime) )
964 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*itr_team[BG_TEAM_ALLIANCE]), MaxPlayersPerTeam);
965 break;
969 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue
970 if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
972 itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE];
973 ++itr_team[BG_TEAM_HORDE];
974 for(; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE]))
976 if( !(*itr_team[BG_TEAM_HORDE])->IsInvitedToBGInstanceGUID
977 && (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating)
978 || (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime) )
980 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*itr_team[BG_TEAM_HORDE]), MaxPlayersPerTeam);
981 break;
986 //if we have 2 teams, then start new arena and invite players!
987 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
989 BattleGround* arena = NULL;
990 if (!(arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, true)))
992 sLog.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
993 return;
996 (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating;
997 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating);
998 (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating;
999 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating);
1000 // 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
1001 if ((*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE)
1003 // add to alliance queue
1004 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE]));
1005 // erase from horde queue
1006 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]);
1007 itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
1009 if ((*(itr_team[BG_TEAM_HORDE]))->Team != HORDE)
1011 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE]));
1012 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]);
1013 itr_team[BG_TEAM_HORDE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin();
1016 InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE);
1017 InviteGroupToBG(*(itr_team[BG_TEAM_HORDE]), arena, HORDE);
1019 sLog.outDebug("Starting rated arena match!");
1021 arena->StartBattleGround();
1026 /*********************************************************/
1027 /*** BATTLEGROUND QUEUE EVENTS ***/
1028 /*********************************************************/
1030 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1032 Player* plr = sObjectMgr.GetPlayer( m_PlayerGuid );
1033 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1034 if (!plr)
1035 return true;
1037 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1038 //if battleground ended and its instance deleted - do nothing
1039 if (!bg)
1040 return true;
1042 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1043 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1044 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue or in battleground
1046 // check if player is invited to this bg
1047 BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId];
1048 if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime))
1050 WorldPacket data;
1051 //we must send remaining time in queue
1052 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, m_ArenaType);
1053 plr->GetSession()->SendPacket(&data);
1056 return true; //event will be deleted
1059 void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
1061 //do nothing
1065 this event has many possibilities when it is executed:
1066 1. player is in battleground ( he clicked enter on invitation window )
1067 2. player left battleground queue and he isn't there any more
1068 3. player left battleground queue and he joined it again and IsInvitedToBGInstanceGUID = 0
1069 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
1070 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
1071 we must remove player in the 5. case even if battleground object doesn't exist!
1073 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1075 Player* plr = sObjectMgr.GetPlayer( m_PlayerGuid );
1076 if (!plr)
1077 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1078 return true;
1080 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1081 //battleground can be deleted already when we are removing queue info
1082 //bg pointer can be NULL! so use it carefully!
1084 uint32 queueSlot = plr->GetBattleGroundQueueIndex(m_BgQueueTypeId);
1085 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue, or in Battleground
1087 // check if player is in queue for this BG and if we are removing his invite event
1088 BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId];
1089 if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime))
1091 sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
1093 plr->RemoveBattleGroundQueueId(m_BgQueueTypeId);
1094 bgQueue.RemovePlayer(m_PlayerGuid, true);
1095 //update queues if battleground isn't ended
1096 if (bg && bg->isBattleGround() && bg->GetStatus() != STATUS_WAIT_LEAVE)
1097 sBattleGroundMgr.ScheduleQueueUpdate(0, 0, m_BgQueueTypeId, m_BgTypeId, bg->GetQueueId());
1099 WorldPacket data;
1100 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
1101 plr->GetSession()->SendPacket(&data);
1105 //event will be deleted
1106 return true;
1109 void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
1111 //do nothing
1114 /*********************************************************/
1115 /*** BATTLEGROUND MANAGER ***/
1116 /*********************************************************/
1118 BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
1120 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1121 m_BattleGrounds[i].clear();
1122 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1123 m_Testing=false;
1126 BattleGroundMgr::~BattleGroundMgr()
1128 DeleteAllBattleGrounds();
1131 void BattleGroundMgr::DeleteAllBattleGrounds()
1133 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1135 for(BattleGroundSet::iterator itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end();)
1137 BattleGround * bg = itr->second;
1138 m_BattleGrounds[i].erase(itr++);
1139 if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
1140 m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
1141 delete bg;
1145 // destroy template battlegrounds that listed only in queues (other already terminated)
1146 for(uint32 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId)
1148 // ~BattleGround call unregistring BG from queue
1149 while(!BGFreeSlotQueue[bgTypeId].empty())
1150 delete BGFreeSlotQueue[bgTypeId].front();
1154 // used to update running battlegrounds, and delete finished ones
1155 void BattleGroundMgr::Update(uint32 diff)
1157 BattleGroundSet::iterator itr, next;
1158 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1160 itr = m_BattleGrounds[i].begin();
1161 // skip updating battleground template
1162 if (itr != m_BattleGrounds[i].end())
1163 ++itr;
1164 for(; itr != m_BattleGrounds[i].end(); itr = next)
1166 next = itr;
1167 ++next;
1168 itr->second->Update(diff);
1169 // use the SetDeleteThis variable
1170 // direct deletion caused crashes
1171 if (itr->second->m_SetDeleteThis)
1173 BattleGround * bg = itr->second;
1174 m_BattleGrounds[i].erase(itr);
1175 if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
1176 m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
1177 delete bg;
1182 // update scheduled queues
1183 if (!m_QueueUpdateScheduler.empty())
1185 std::vector<uint64> scheduled;
1187 //create mutex
1188 //ACE_Guard<ACE_Thread_Mutex> guard(SchedulerLock);
1189 //copy vector and clear the other
1190 scheduled = std::vector<uint64>(m_QueueUpdateScheduler);
1191 m_QueueUpdateScheduler.clear();
1192 //release lock
1195 for (uint8 i = 0; i < scheduled.size(); i++)
1197 uint32 arenaRating = scheduled[i] >> 32;
1198 uint8 arenaType = scheduled[i] >> 24 & 255;
1199 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundQueueTypeId(scheduled[i] >> 16 & 255);
1200 BattleGroundTypeId bgTypeId = BattleGroundTypeId((scheduled[i] >> 8) & 255);
1201 BGQueueIdBasedOnLevel queue_id = BGQueueIdBasedOnLevel(scheduled[i] & 255);
1202 m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, queue_id, arenaType, arenaRating > 0, arenaRating);
1206 // if rating difference counts, maybe force-update queues
1207 if (sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER))
1209 // it's time to force update
1210 if (m_NextRatingDiscardUpdate < diff)
1212 // forced update for level 70 rated arenas
1213 sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
1214 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_2v2, true, 0);
1215 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_2v2, true, 0);
1216 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_3v3, true, 0);
1217 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_3v3, true, 0);
1218 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_5v5, true, 0);
1219 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_5v5, true, 0);
1220 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1222 else
1223 m_NextRatingDiscardUpdate -= diff;
1225 if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1227 if (m_AutoDistributionTimeChecker < diff)
1229 if (sWorld.GetGameTime() > m_NextAutoDistributionTime)
1231 DistributeArenaPoints();
1232 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1233 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"UI64FMTD"'", uint64(m_NextAutoDistributionTime));
1235 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1237 else
1238 m_AutoDistributionTimeChecker -= diff;
1242 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype)
1244 // we can be in 2 queues in same time...
1246 if (StatusID == 0 || !bg)
1248 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4+8);
1249 *data << uint32(QueueSlot); // queue id (0...1)
1250 *data << uint64(0);
1251 return;
1254 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+8+1+1+4+1+4+4+4));
1255 *data << uint32(QueueSlot); // queue id (0...1) - player can be in 2 queues in time
1256 // uint64 in client
1257 *data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1258 *data << uint8(0); // 3.3.0
1259 *data << uint8(0); // 3.3.0
1260 *data << uint32(bg->GetClientInstanceID());
1261 // alliance/horde for BG and skirmish/rated for Arenas
1262 // following displays the minimap-icon 0 = faction icon 1 = arenaicon
1263 *data << uint8(bg->isRated());
1264 *data << uint32(StatusID); // status
1265 switch(StatusID)
1267 case STATUS_WAIT_QUEUE: // status_in_queue
1268 *data << uint32(Time1); // average wait time, milliseconds
1269 *data << uint32(Time2); // time in queue, updated every minute!, milliseconds
1270 break;
1271 case STATUS_WAIT_JOIN: // status_invite
1272 *data << uint32(bg->GetMapId()); // map id
1273 *data << uint32(Time1); // time to remove from queue, milliseconds
1274 break;
1275 case STATUS_IN_PROGRESS: // status_in_progress
1276 *data << uint32(bg->GetMapId()); // map id
1277 *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
1278 *data << uint32(Time2); // time from bg start, milliseconds
1279 *data << uint8(0x1); // unk sometimes 0x0!
1280 break;
1281 default:
1282 sLog.outError("Unknown BG status!");
1283 break;
1287 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1289 uint8 type = (bg->isArena() ? 1 : 0);
1290 // last check on 3.0.3
1291 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1292 *data << uint8(type); // type (battleground=0/arena=1)
1294 if(type) // arena
1296 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1297 for(int i = 1; i >= 0; --i)
1299 *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
1300 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1301 *data << uint32(0); // added again in 3.1
1302 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1304 for(int i = 1; i >= 0; --i)
1306 uint32 at_id = bg->m_ArenaTeamIds[i];
1307 ArenaTeam * at = sObjectMgr.GetArenaTeamById(at_id);
1308 if (at)
1309 *data << at->GetName();
1310 else
1311 *data << (uint8)0;
1315 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
1317 *data << uint8(0); // bg not ended
1319 else
1321 *data << uint8(1); // bg ended
1322 *data << uint8(bg->GetWinner()); // who win
1325 *data << (int32)(bg->GetPlayerScoresSize());
1327 for(BattleGround::BattleGroundScoreMap::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1329 *data << (uint64)itr->first;
1330 *data << (int32)itr->second->KillingBlows;
1331 if (type == 0)
1333 *data << (int32)itr->second->HonorableKills;
1334 *data << (int32)itr->second->Deaths;
1335 *data << (int32)(itr->second->BonusHonor);
1337 else
1339 Player *plr = sObjectMgr.GetPlayer(itr->first);
1340 uint32 team = bg->GetPlayerTeam(itr->first);
1341 if (!team && plr)
1342 team = plr->GetTeam();
1343 if (( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ))
1344 *data << uint8(1);
1345 else
1346 *data << uint8(0);
1348 *data << (int32)itr->second->DamageDone; // damage done
1349 *data << (int32)itr->second->HealingDone; // healing done
1350 switch(bg->GetTypeID()) // battleground specific things
1352 case BATTLEGROUND_AV:
1353 *data << (uint32)0x00000005; // count of next fields
1354 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1355 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1356 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1357 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1358 *data << (uint32)((BattleGroundAVScore*)itr->second)->SecondaryObjectives; // SecondaryObjectives - free some of the Lieutnants
1359 break;
1360 case BATTLEGROUND_WS:
1361 *data << (uint32)0x00000002; // count of next fields
1362 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1363 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1364 break;
1365 case BATTLEGROUND_AB:
1366 *data << (uint32)0x00000002; // count of next fields
1367 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1368 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1369 break;
1370 case BATTLEGROUND_EY:
1371 *data << (uint32)0x00000001; // count of next fields
1372 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1373 break;
1374 case BATTLEGROUND_NA:
1375 case BATTLEGROUND_BE:
1376 case BATTLEGROUND_AA:
1377 case BATTLEGROUND_RL:
1378 case BATTLEGROUND_SA: // wotlk
1379 case BATTLEGROUND_DS: // wotlk
1380 case BATTLEGROUND_RV: // wotlk
1381 case BATTLEGROUND_IC: // wotlk
1382 case BATTLEGROUND_ABG: // wotlk
1383 *data << (int32)0; // 0
1384 break;
1385 default:
1386 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1387 *data << (int32)0;
1388 break;
1393 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
1395 /*bgTypeId is:
1396 0 - Your group has joined a battleground queue, but you are not eligible
1397 1 - Your group has joined the queue for AV
1398 2 - Your group has joined the queue for WS
1399 3 - Your group has joined the queue for AB
1400 4 - Your group has joined the queue for NA
1401 5 - Your group has joined the queue for BE Arena
1402 6 - Your group has joined the queue for All Arenas
1403 7 - Your group has joined the queue for EotS*/
1404 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1405 *data << uint32(bgTypeId);
1408 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1410 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1411 *data << uint32(field);
1412 *data << uint32(value);
1415 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1417 data->Initialize(SMSG_PLAY_SOUND, 4);
1418 *data << uint32(soundid);
1421 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid)
1423 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1424 *data << uint64(guid);
1427 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1429 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1430 *data << uint64(plr->GetGUID());
1433 BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId)
1435 //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from
1436 //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
1437 BattleGround* bg = GetBattleGroundTemplate(bgTypeId);
1438 if (!bg)
1439 return NULL;
1441 if (bg->isArena())
1442 return GetBattleGround(instanceId, bgTypeId);
1444 for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr)
1446 if (itr->second->GetClientInstanceID() == instanceId)
1447 return itr->second;
1449 return NULL;
1452 BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
1454 //search if needed
1455 BattleGroundSet::iterator itr;
1456 if (bgTypeId == BATTLEGROUND_TYPE_NONE)
1458 for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1460 itr = m_BattleGrounds[i].find(InstanceID);
1461 if (itr != m_BattleGrounds[i].end())
1462 return itr->second;
1464 return NULL;
1466 itr = m_BattleGrounds[bgTypeId].find(InstanceID);
1467 return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL );
1470 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
1472 //map is sorted and we can be sure that lowest instance id has only BG template
1473 return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second;
1476 uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
1478 if (IsArenaType(bgTypeId))
1479 return 0; //arenas don't have client-instanceids
1481 // we create here an instanceid, which is just for
1482 // displaying this to the client and without any other use..
1483 // the client-instanceIds are unique for each battleground-type
1484 // the instance-id just needs to be as low as possible, beginning with 1
1485 // the following works, because std::set is default ordered with "<"
1486 // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
1487 uint32 lastId = 0;
1488 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();)
1490 if( (++lastId) != *itr) //if there is a gap between the ids, we will break..
1491 break;
1492 lastId = *itr;
1494 m_ClientBattleGroundIds[bgTypeId][queue_id].insert(lastId + 1);
1495 return lastId + 1;
1498 // create a new battleground that will really be used to play
1499 BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated)
1501 // get the template BG
1502 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1503 if (!bg_template)
1505 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1506 return NULL;
1509 //for arenas there is random map used
1510 if (bg_template->isArena())
1512 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
1513 uint32 arena_num = urand(0,2);
1514 bgTypeId = arenas[arena_num];
1515 bg_template = GetBattleGroundTemplate(bgTypeId);
1516 if (!bg_template)
1518 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1519 return NULL;
1523 BattleGround *bg = NULL;
1524 // create a copy of the BG template
1525 switch(bgTypeId)
1527 case BATTLEGROUND_AV:
1528 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1529 break;
1530 case BATTLEGROUND_WS:
1531 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1532 break;
1533 case BATTLEGROUND_AB:
1534 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1535 break;
1536 case BATTLEGROUND_NA:
1537 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1538 break;
1539 case BATTLEGROUND_BE:
1540 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1541 break;
1542 case BATTLEGROUND_AA:
1543 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1544 break;
1545 case BATTLEGROUND_EY:
1546 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1547 break;
1548 case BATTLEGROUND_RL:
1549 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1550 break;
1551 case BATTLEGROUND_SA:
1552 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1553 break;
1554 case BATTLEGROUND_DS:
1555 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1556 break;
1557 case BATTLEGROUND_RV:
1558 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1559 break;
1560 case BATTLEGROUND_IC:
1561 bg = new BattleGroundIC(*(BattleGroundIC*)bg_template);
1562 break;
1563 case BATTLEGROUND_ABG:
1564 bg = new BattleGroundABG(*(BattleGroundABG*)bg_template);
1565 break;
1566 default:
1567 //error, but it is handled few lines above
1568 return 0;
1571 // generate a new instance id
1572 bg->SetInstanceID(sMapMgr.GenerateInstanceId()); // set instance id
1573 bg->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId, queue_id));
1575 // reset the new bg (set status to status_wait_queue from status_none)
1576 bg->Reset();
1578 // start the joining of the bg
1579 bg->SetStatus(STATUS_WAIT_JOIN);
1580 bg->SetQueueId(queue_id);
1581 bg->SetArenaType(arenaType);
1582 bg->SetRated(isRated);
1584 return bg;
1587 // used to create the BG templates
1588 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)
1590 // Create the BG
1591 BattleGround *bg = NULL;
1592 switch(bgTypeId)
1594 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1595 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1596 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1597 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1598 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1599 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1600 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1601 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1602 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1603 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1604 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1605 case BATTLEGROUND_IC: bg = new BattleGroundIC; break;
1606 case BATTLEGROUND_ABG: bg = new BattleGroundABG; break;
1607 default:bg = new BattleGround; break; // placeholder for non implemented BG
1610 bg->SetMapId(MapID);
1611 bg->SetTypeID(bgTypeId);
1612 bg->SetInstanceID(0);
1613 bg->SetArenaorBGType(IsArena);
1614 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1615 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1616 bg->SetMinPlayers(MinPlayersPerTeam * 2);
1617 bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
1618 bg->SetName(BattleGroundName);
1619 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1620 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1621 bg->SetLevelRange(LevelMin, LevelMax);
1623 // add bg to update list
1624 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1626 // return some not-null value, bgTypeId is good enough for me
1627 return bgTypeId;
1630 void BattleGroundMgr::CreateInitialBattleGrounds()
1632 float AStartLoc[4];
1633 float HStartLoc[4];
1634 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1635 BattlemasterListEntry const *bl;
1636 WorldSafeLocsEntry const *start;
1637 bool IsArena;
1639 uint32 count = 0;
1641 // 0 1 2 3 4 5 6 7 8
1642 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1644 if (!result)
1646 barGoLink bar(1);
1648 bar.step();
1650 sLog.outString();
1651 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1652 return;
1655 barGoLink bar(result->GetRowCount());
1659 Field *fields = result->Fetch();
1660 bar.step();
1662 uint32 bgTypeID_ = fields[0].GetUInt32();
1664 // can be overwrite by values from DB
1665 bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
1666 if (!bl)
1668 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
1669 continue;
1672 BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
1674 IsArena = (bl->type == TYPE_ARENA);
1675 MinPlayersPerTeam = fields[1].GetUInt32();
1676 MaxPlayersPerTeam = fields[2].GetUInt32();
1677 MinLvl = fields[3].GetUInt32();
1678 MaxLvl = fields[4].GetUInt32();
1679 //check values from DB
1680 if (MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam)
1682 MaxPlayersPerTeam = bl->maxplayersperteam;
1683 MinPlayersPerTeam = bl->maxplayersperteam / 2;
1685 if (MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl)
1687 // TODO: fix me
1688 MinLvl = 0;//bl->minlvl;
1689 MaxLvl = 80;//bl->maxlvl;
1692 start1 = fields[5].GetUInt32();
1694 start = sWorldSafeLocsStore.LookupEntry(start1);
1695 if (start)
1697 AStartLoc[0] = start->x;
1698 AStartLoc[1] = start->y;
1699 AStartLoc[2] = start->z;
1700 AStartLoc[3] = fields[6].GetFloat();
1702 else if (bgTypeID == BATTLEGROUND_AA || bgTypeID == BATTLEGROUND_ABG)
1704 AStartLoc[0] = 0;
1705 AStartLoc[1] = 0;
1706 AStartLoc[2] = 0;
1707 AStartLoc[3] = fields[6].GetFloat();
1709 else
1711 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
1712 continue;
1715 start2 = fields[7].GetUInt32();
1717 start = sWorldSafeLocsStore.LookupEntry(start2);
1718 if (start)
1720 HStartLoc[0] = start->x;
1721 HStartLoc[1] = start->y;
1722 HStartLoc[2] = start->z;
1723 HStartLoc[3] = fields[8].GetFloat();
1725 else if (bgTypeID == BATTLEGROUND_AA || bgTypeID == BATTLEGROUND_ABG)
1727 HStartLoc[0] = 0;
1728 HStartLoc[1] = 0;
1729 HStartLoc[2] = 0;
1730 HStartLoc[3] = fields[8].GetFloat();
1732 else
1734 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
1735 continue;
1738 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1739 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]))
1740 continue;
1742 ++count;
1743 } while (result->NextRow());
1745 delete result;
1747 sLog.outString();
1748 sLog.outString( ">> Loaded %u battlegrounds", count );
1751 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1753 if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1755 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1756 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1757 if (!result)
1759 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1760 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1761 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"UI64FMTD"')", uint64(m_NextAutoDistributionTime));
1763 else
1765 m_NextAutoDistributionTime = time_t((*result)[0].GetUInt64());
1766 delete result;
1768 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1772 void BattleGroundMgr::DistributeArenaPoints()
1774 // used to distribute arena points based on last week's stats
1775 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
1777 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
1779 //temporary structure for storing maximum points to add values for all players
1780 std::map<uint32, uint32> PlayerPoints;
1782 //at first update all points for all team members
1783 for(ObjectMgr::ArenaTeamMap::iterator team_itr = sObjectMgr.GetArenaTeamMapBegin(); team_itr != sObjectMgr.GetArenaTeamMapEnd(); ++team_itr)
1785 if (ArenaTeam * at = team_itr->second)
1787 at->UpdateArenaPointsHelper(PlayerPoints);
1791 //cycle that gives points to all players
1792 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1794 //update to database
1795 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
1796 //add points if player is online
1797 Player* pl = sObjectMgr.GetPlayer(plr_itr->first);
1798 if (pl)
1799 pl->ModifyArenaPoints(plr_itr->second);
1802 PlayerPoints.clear();
1804 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
1806 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
1807 for(ObjectMgr::ArenaTeamMap::iterator titr = sObjectMgr.GetArenaTeamMapBegin(); titr != sObjectMgr.GetArenaTeamMapEnd(); ++titr)
1809 if (ArenaTeam * at = titr->second)
1811 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1812 at->SaveToDB(); // save changes
1813 at->NotifyStatsChanged(); // notify the players of the changes
1817 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
1819 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
1822 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId, uint8 fromWhere)
1824 if (!plr)
1825 return;
1827 uint32 PlayerLevel = 10;
1828 PlayerLevel = plr->getLevel();
1830 data->Initialize(SMSG_BATTLEFIELD_LIST);
1831 *data << uint64(guid); // battlemaster guid
1832 *data << uint8(fromWhere); // from where you joined
1833 *data << uint32(bgTypeId); // battleground id
1834 if(bgTypeId == BATTLEGROUND_AA) // arena
1836 *data << uint8(4); // unk
1837 *data << uint8(0); // unk
1838 *data << uint32(0); // unk (count?)
1840 else // battleground
1842 *data << uint8(0); // unk, different for each bg type
1843 *data << uint8(0); // unk
1845 size_t count_pos = data->wpos();
1846 uint32 count = 0;
1847 *data << uint32(0); // number of bg instances
1849 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
1850 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();++itr)
1852 *data << uint32(*itr);
1853 ++count;
1855 data->put<uint32>( count_pos , count);
1859 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId)
1861 BattleGround *bg = GetBattleGround(instanceId, bgTypeId);
1862 if (bg)
1864 uint32 mapid = bg->GetMapId();
1865 float x, y, z, O;
1866 uint32 team = pl->GetBGTeam();
1867 if (team==0)
1868 team = pl->GetTeam();
1869 bg->GetTeamStartLoc(team, x, y, z, O);
1871 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1872 pl->TeleportTo(mapid, x, y, z, O);
1874 else
1876 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1880 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
1882 return ( bgTypeId == BATTLEGROUND_AA ||
1883 bgTypeId == BATTLEGROUND_BE ||
1884 bgTypeId == BATTLEGROUND_NA ||
1885 bgTypeId == BATTLEGROUND_RL );
1888 BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
1890 switch(bgTypeId)
1892 case BATTLEGROUND_WS:
1893 return BATTLEGROUND_QUEUE_WS;
1894 case BATTLEGROUND_AB:
1895 return BATTLEGROUND_QUEUE_AB;
1896 case BATTLEGROUND_AV:
1897 return BATTLEGROUND_QUEUE_AV;
1898 case BATTLEGROUND_EY:
1899 return BATTLEGROUND_QUEUE_EY;
1900 case BATTLEGROUND_SA:
1901 return BATTLEGROUND_QUEUE_SA;
1902 case BATTLEGROUND_IC:
1903 return BATTLEGROUND_QUEUE_IC;
1904 case BATTLEGROUND_ABG:
1905 return BATTLEGROUND_QUEUE_NONE;
1906 case BATTLEGROUND_AA:
1907 case BATTLEGROUND_NA:
1908 case BATTLEGROUND_RL:
1909 case BATTLEGROUND_BE:
1910 case BATTLEGROUND_DS:
1911 case BATTLEGROUND_RV:
1912 switch(arenaType)
1914 case ARENA_TYPE_2v2:
1915 return BATTLEGROUND_QUEUE_2v2;
1916 case ARENA_TYPE_3v3:
1917 return BATTLEGROUND_QUEUE_3v3;
1918 case ARENA_TYPE_5v5:
1919 return BATTLEGROUND_QUEUE_5v5;
1920 default:
1921 return BATTLEGROUND_QUEUE_NONE;
1923 default:
1924 return BATTLEGROUND_QUEUE_NONE;
1928 BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId)
1930 switch(bgQueueTypeId)
1932 case BATTLEGROUND_QUEUE_WS:
1933 return BATTLEGROUND_WS;
1934 case BATTLEGROUND_QUEUE_AB:
1935 return BATTLEGROUND_AB;
1936 case BATTLEGROUND_QUEUE_AV:
1937 return BATTLEGROUND_AV;
1938 case BATTLEGROUND_QUEUE_EY:
1939 return BATTLEGROUND_EY;
1940 case BATTLEGROUND_QUEUE_SA:
1941 return BATTLEGROUND_SA;
1942 case BATTLEGROUND_QUEUE_IC:
1943 return BATTLEGROUND_IC;
1944 case BATTLEGROUND_QUEUE_2v2:
1945 case BATTLEGROUND_QUEUE_3v3:
1946 case BATTLEGROUND_QUEUE_5v5:
1947 return BATTLEGROUND_AA;
1948 default:
1949 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
1953 uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId)
1955 switch(bgQueueTypeId)
1957 case BATTLEGROUND_QUEUE_2v2:
1958 return ARENA_TYPE_2v2;
1959 case BATTLEGROUND_QUEUE_3v3:
1960 return ARENA_TYPE_3v3;
1961 case BATTLEGROUND_QUEUE_5v5:
1962 return ARENA_TYPE_5v5;
1963 default:
1964 return 0;
1968 void BattleGroundMgr::ToggleTesting()
1970 m_Testing = !m_Testing;
1971 if (m_Testing)
1972 sWorld.SendWorldText(LANG_DEBUG_BG_ON);
1973 else
1974 sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
1977 void BattleGroundMgr::ToggleArenaTesting()
1979 m_ArenaTesting = !m_ArenaTesting;
1980 if (m_ArenaTesting)
1981 sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
1982 else
1983 sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
1986 void BattleGroundMgr::ScheduleQueueUpdate(uint32 arenaRating, uint8 arenaType, BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
1988 //ACE_Guard<ACE_Thread_Mutex> guard(SchedulerLock);
1989 //we will use only 1 number created of bgTypeId and queue_id
1990 uint64 schedule_id = ((uint64)arenaRating << 32) | (arenaType << 24) | (bgQueueTypeId << 16) | (bgTypeId << 8) | queue_id;
1991 bool found = false;
1992 for (uint8 i = 0; i < m_QueueUpdateScheduler.size(); i++)
1994 if (m_QueueUpdateScheduler[i] == schedule_id)
1996 found = true;
1997 break;
2000 if (!found)
2001 m_QueueUpdateScheduler.push_back(schedule_id);
2004 uint32 BattleGroundMgr::GetMaxRatingDifference() const
2006 // this is for stupid people who can't use brain and set max rating difference to 0
2007 uint32 diff = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
2008 if (diff == 0)
2009 diff = 5000;
2010 return diff;
2013 uint32 BattleGroundMgr::GetRatingDiscardTimer() const
2015 return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
2018 uint32 BattleGroundMgr::GetPrematureFinishTime() const
2020 return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
2023 void BattleGroundMgr::LoadBattleMastersEntry()
2025 mBattleMastersMap.clear(); // need for reload case
2027 QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
2029 uint32 count = 0;
2031 if (!result)
2033 barGoLink bar( 1 );
2034 bar.step();
2036 sLog.outString();
2037 sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
2038 return;
2041 barGoLink bar( result->GetRowCount() );
2045 ++count;
2046 bar.step();
2048 Field *fields = result->Fetch();
2050 uint32 entry = fields[0].GetUInt32();
2051 uint32 bgTypeId = fields[1].GetUInt32();
2052 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
2054 sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
2055 continue;
2058 mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
2060 } while( result->NextRow() );
2062 delete result;
2064 sLog.outString();
2065 sLog.outString( ">> Loaded %u battlemaster entries", count );
2068 bool BattleGroundMgr::IsBGWeekend(BattleGroundTypeId bgTypeId)
2070 switch (bgTypeId)
2072 case BATTLEGROUND_AV:
2073 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_AV);
2074 case BATTLEGROUND_EY:
2075 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_EY);
2076 case BATTLEGROUND_WS:
2077 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_WS);
2078 case BATTLEGROUND_SA:
2079 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_SA);
2080 default:
2081 return false;
2085 void BattleGroundMgr::LoadBattleEventIndexes()
2087 BattleGroundEventIdx events;
2088 events.event1 = BG_EVENT_NONE;
2089 events.event2 = BG_EVENT_NONE;
2090 m_GameObjectBattleEventIndexMap.clear(); // need for reload case
2091 m_GameObjectBattleEventIndexMap[-1] = events;
2092 m_CreatureBattleEventIndexMap.clear(); // need for reload case
2093 m_CreatureBattleEventIndexMap[-1] = events;
2095 uint32 count = 0;
2097 QueryResult *result =
2098 // 0 1 2 3 4 5 6
2099 WorldDatabase.PQuery( "SELECT data.typ, data.guid1, data.ev1 AS ev1, data.ev2 AS ev2, data.map AS m, data.guid2, description.map, "
2100 // 7 8 9
2101 "description.event1, description.event2, description.description "
2102 "FROM "
2103 "(SELECT '1' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2104 "FROM gameobject_battleground AS a "
2105 "LEFT OUTER JOIN gameobject AS b ON a.guid = b.guid "
2106 "UNION "
2107 "SELECT '2' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2108 "FROM creature_battleground AS a "
2109 "LEFT OUTER JOIN creature AS b ON a.guid = b.guid "
2110 ") data "
2111 "RIGHT OUTER JOIN battleground_events AS description ON data.map = description.map "
2112 "AND data.ev1 = description.event1 AND data.ev2 = description.event2 "
2113 // full outer join doesn't work in mysql :-/ so just UNION-select the same again and add a left outer join
2114 "UNION "
2115 "SELECT data.typ, data.guid1, data.ev1, data.ev2, data.map, data.guid2, description.map, "
2116 "description.event1, description.event2, description.description "
2117 "FROM "
2118 "(SELECT '1' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2119 "FROM gameobject_battleground AS a "
2120 "LEFT OUTER JOIN gameobject AS b ON a.guid = b.guid "
2121 "UNION "
2122 "SELECT '2' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2123 "FROM creature_battleground AS a "
2124 "LEFT OUTER JOIN creature AS b ON a.guid = b.guid "
2125 ") data "
2126 "LEFT OUTER JOIN battleground_events AS description ON data.map = description.map "
2127 "AND data.ev1 = description.event1 AND data.ev2 = description.event2 "
2128 "ORDER BY m, ev1, ev2" );
2129 if(!result)
2131 barGoLink bar(1);
2132 bar.step();
2134 sLog.outString();
2135 sLog.outErrorDb(">> Loaded 0 battleground eventindexes.");
2136 return;
2139 barGoLink bar(result->GetRowCount());
2143 bar.step();
2144 Field *fields = result->Fetch();
2145 if (fields[2].GetUInt8() == BG_EVENT_NONE || fields[3].GetUInt8() == BG_EVENT_NONE)
2146 continue; // we don't need to add those to the eventmap
2148 bool gameobject = (fields[0].GetUInt8() == 1);
2149 uint32 dbTableGuidLow = fields[1].GetUInt32();
2150 events.event1 = fields[2].GetUInt8();
2151 events.event2 = fields[3].GetUInt8();
2152 uint32 map = fields[4].GetUInt32();
2154 uint32 desc_map = fields[6].GetUInt32();
2155 uint8 desc_event1 = fields[7].GetUInt8();
2156 uint8 desc_event2 = fields[8].GetUInt8();
2157 const char *description = fields[9].GetString();
2159 // checking for NULL - through right outer join this will mean following:
2160 if (fields[5].GetUInt32() != dbTableGuidLow)
2162 sLog.outErrorDb("BattleGroundEvent: %s with nonexistant guid %u for event: map:%u, event1:%u, event2:%u (\"%s\")",
2163 (gameobject) ? "gameobject" : "creature", dbTableGuidLow, map, events.event1, events.event2, description);
2164 continue;
2167 // checking for NULL - through full outer join this can mean 2 things:
2168 if (desc_map != map)
2170 // there is an event missing
2171 if (dbTableGuidLow == 0)
2173 sLog.outErrorDb("BattleGroundEvent: missing db-data for map:%u, event1:%u, event2:%u (\"%s\")", desc_map, desc_event1, desc_event2, description);
2174 continue;
2176 // we have an event which shouldn't exist
2177 else
2179 sLog.outErrorDb("BattleGroundEvent: %s with guid %u is registered, for a nonexistant event: map:%u, event1:%u, event2:%u",
2180 (gameobject) ? "gameobject" : "creature", dbTableGuidLow, map, events.event1, events.event2);
2181 continue;
2185 if (gameobject)
2186 m_GameObjectBattleEventIndexMap[dbTableGuidLow] = events;
2187 else
2188 m_CreatureBattleEventIndexMap[dbTableGuidLow] = events;
2190 ++count;
2192 } while(result->NextRow());
2194 sLog.outString();
2195 sLog.outString( ">> Loaded %u battleground eventindexes", count);
2196 delete result;