[7607] Improvements in support some generic achievement classes
[AHbot.git] / src / game / BattleGroundMgr.cpp
blobfad0a40f4330ca7b00251968b4555426bef077f4
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "SharedDefines.h"
21 #include "Player.h"
22 #include "BattleGroundMgr.h"
23 #include "BattleGroundAV.h"
24 #include "BattleGroundAB.h"
25 #include "BattleGroundEY.h"
26 #include "BattleGroundWS.h"
27 #include "BattleGroundNA.h"
28 #include "BattleGroundBE.h"
29 #include "BattleGroundAA.h"
30 #include "BattleGroundRL.h"
31 #include "BattleGroundSA.h"
32 #include "BattleGroundDS.h"
33 #include "BattleGroundRV.h"
34 #include "MapManager.h"
35 #include "Map.h"
36 #include "MapInstanced.h"
37 #include "ObjectMgr.h"
38 #include "ProgressBar.h"
39 #include "Chat.h"
40 #include "ArenaTeam.h"
41 #include "World.h"
42 #include "WorldPacket.h"
43 #include "ProgressBar.h"
45 #include "Policies/SingletonImp.h"
47 INSTANTIATE_SINGLETON_1( BattleGroundMgr );
49 /*********************************************************/
50 /*** BATTLEGROUND QUEUE SYSTEM ***/
51 /*********************************************************/
53 BattleGroundQueue::BattleGroundQueue()
55 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
57 for(uint32 j = 0; j < MAX_BATTLEGROUND_QUEUES; j++)
59 m_SumOfWaitTimes[i][j] = 0;
60 m_WaitTimeLastPlayer[i][j] = 0;
61 for(uint32 k = 0; k < COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME; k++)
62 m_WaitTimes[i][j][k] = 0;
67 BattleGroundQueue::~BattleGroundQueue()
69 m_QueuedPlayers.clear();
70 for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
72 for(uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; j++)
74 for(GroupsQueueType::iterator itr = m_QueuedGroups[i][j].begin(); itr!= m_QueuedGroups[i][j].end(); ++itr)
75 delete (*itr);
76 m_QueuedGroups[i][j].clear();
81 /*********************************************************/
82 /*** BATTLEGROUND QUEUE SELECTION POOLS ***/
83 /*********************************************************/
85 // selection pool initialization, used to clean up from prev selection
86 void BattleGroundQueue::SelectionPool::Init()
88 SelectedGroups.clear();
89 PlayerCount = 0;
92 // remove group info from selection pool
93 // returns true when we need to try to add new group to selection pool
94 // returns false when selection pool is ok or when we kicked smaller group than we need to kick
95 // sometimes it can be called on empty selection pool
96 bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size)
98 //find maxgroup or LAST group with size == size and kick it
99 bool found = false;
100 GroupsQueueType::iterator groupToKick = SelectedGroups.begin();
101 for (GroupsQueueType::iterator itr = groupToKick; itr != SelectedGroups.end(); ++itr)
103 if( abs((int32)((*itr)->Players.size() - size)) <= 1 )
105 groupToKick = itr;
106 found = true;
108 else if (!found && (*itr)->Players.size() >= (*groupToKick)->Players.size())
109 groupToKick = itr;
111 //if pool is empty, do nothing
112 if( GetPlayerCount() )
114 //update player count
115 GroupQueueInfo* ginfo = (*groupToKick);
116 SelectedGroups.erase(groupToKick);
117 PlayerCount -= ginfo->Players.size();
118 //return false if we kicked smaller group or there are enough players in selection pool
119 if (ginfo->Players.size() <= size + 1)
120 return false;
122 return true;
125 // add group to selection pool
126 // used when building selection pools
127 // returns true if we can invite more players, or when we added group to selection pool
128 // returns false when selection pool is full
129 bool BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount)
131 //if group is larger than desired count - don't allow to add it to pool
132 if( !ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size() )
134 SelectedGroups.push_back(ginfo);
135 // increase selected players count
136 PlayerCount += ginfo->Players.size();
137 return true;
139 if( PlayerCount < desiredCount )
140 return true;
141 return false;
144 /*********************************************************/
145 /*** BATTLEGROUND QUEUES ***/
146 /*********************************************************/
148 // add group to bg queue with the given leader and bg specifications
149 GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId BgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 arenateamid)
151 BGQueueIdBasedOnLevel queue_id = leader->GetBattleGroundQueueIdFromLevel(BgTypeId);
153 // create new ginfo
154 // cannot use the method like in addplayer, because that could modify an in-queue group's stats
155 // (e.g. leader leaving queue then joining as individual again)
156 GroupQueueInfo* ginfo = new GroupQueueInfo;
157 ginfo->BgTypeId = BgTypeId;
158 ginfo->ArenaType = ArenaType;
159 ginfo->ArenaTeamId = arenateamid;
160 ginfo->IsRated = isRated;
161 ginfo->IsInvitedToBGInstanceGUID = 0;
162 ginfo->JoinTime = getMSTime();
163 ginfo->RemoveInviteTime = 0;
164 ginfo->Team = leader->GetTeam();
165 ginfo->ArenaTeamRating = arenaRating;
166 ginfo->OpponentsTeamRating = 0;
168 ginfo->Players.clear();
170 //compute index (if group is premade or joined a rated match) to queues
171 uint32 index = 0;
172 if(!isRated && !isPremade)
173 index += BG_TEAMS_COUNT;
174 if(ginfo->Team == HORDE)
175 index++;
176 sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index);
178 m_QueuedGroups[queue_id][index].push_back(ginfo);
180 // return ginfo, because it is needed to add players to this group info
181 return ginfo;
184 //add player to playermap
185 void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
187 //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
188 PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()];
189 info.LastOnlineTime = getMSTime();
190 info.GroupInfo = ginfo;
192 // add the pinfo to ginfo's list
193 ginfo->Players[plr->GetGUID()] = &info;
196 void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
198 uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, getMSTime());
199 uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
200 if( !ginfo->ArenaType )
202 if( ginfo->Team == HORDE )
203 team_index = BG_TEAM_HORDE;
205 else
207 if( ginfo->IsRated )
208 team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
211 //store pointer to arrayindex of player that was added first
212 uint32* lastPlayerAddedPointer = &(m_WaitTimeLastPlayer[team_index][queue_id]);
213 //remove his time from sum
214 m_SumOfWaitTimes[team_index][queue_id] -= m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)];
215 //set average time to new
216 m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)] = timeInQueue;
217 //add new time to sum
218 m_SumOfWaitTimes[team_index][queue_id] += timeInQueue;
219 //set index of last player added to next one
220 (*lastPlayerAddedPointer)++;
221 (*lastPlayerAddedPointer) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME;
224 uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
226 uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
227 if( !ginfo->ArenaType )
229 if( ginfo->Team == HORDE )
230 team_index = BG_TEAM_HORDE;
232 else
234 if( ginfo->IsRated )
235 team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
237 //check if there is enought values(we always add values > 0)
238 if(m_WaitTimes[team_index][queue_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] )
239 return (m_SumOfWaitTimes[team_index][queue_id] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME);
240 else
241 //if there aren't enough values return 0 - not available
242 return 0;
245 //remove player from queue and from group info, if group info is empty then remove it too
246 void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
248 //Player *plr = objmgr.GetPlayer(guid);
250 int32 queue_id = -1; // signed for proper for-loop finish
251 QueuedPlayersMap::iterator itr;
253 //remove player from map, if he's there
254 itr = m_QueuedPlayers.find(guid);
255 if( itr == m_QueuedPlayers.end() )
257 sLog.outError("BattleGroundQueue: couldn't find player to remove GUID: %u", GUID_LOPART(guid));
258 return;
261 GroupQueueInfo* group = itr->second.GroupInfo;
262 GroupsQueueType::iterator group_itr, group_itr_tmp;
263 // mostly people with the highest levels are in battlegrounds, thats why
264 // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0
265 // variable index removes useless searching in other team's queue
266 uint32 index = (group->Team == HORDE) ? BG_TEAM_HORDE : BG_TEAM_ALLIANCE;
268 for (int32 queue_id_tmp = MAX_BATTLEGROUND_QUEUES - 1; queue_id_tmp >= 0 && queue_id == -1; --queue_id_tmp)
270 //we must check premade and normal team's queue - because when players from premade are joining bg,
271 //they leave groupinfo so we can't use its players size to find out index
272 for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_QUEUE_NORMAL_ALLIANCE)
274 for(group_itr_tmp = m_QueuedGroups[queue_id_tmp][j].begin(); group_itr_tmp != m_QueuedGroups[queue_id_tmp][j].end(); ++group_itr_tmp)
276 if( (*group_itr_tmp) == group )
278 queue_id = queue_id_tmp;
279 group_itr = group_itr_tmp;
280 //we must store index to be able to erase iterator
281 index = j;
282 break;
287 //player can't be in queue without group, but just in case
288 if( queue_id == -1 )
290 sLog.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid));
291 return;
293 sLog.outDebug("BattleGroundQueue: Removing player GUID %u, from queue_id %u", GUID_LOPART(guid), (uint32)queue_id);
295 // ALL variables are correctly set
296 // We can ignore leveling up in queue - it should not cause crash
297 // remove player from group
298 // if only one player there, remove group
300 // remove player queue info from group queue info
301 std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
302 if( pitr != group->Players.end() )
303 group->Players.erase(pitr);
305 // if invited to bg, and should decrease invited count, then do it
306 if( decreaseInvitedCount && group->IsInvitedToBGInstanceGUID )
308 BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID, group->BgTypeId);
309 if( bg )
310 bg->DecreaseInvitedCount(group->Team);
313 // remove player queue info
314 m_QueuedPlayers.erase(itr);
316 //if we left BG queue(not porting) OR if arena team left queue for rated match
317 if( (decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()) )
318 AnnounceWorld(group, guid, false);
320 //if player leaves queue and he is invited to rated arena match, then he have to loose
321 if( group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount )
323 ArenaTeam * at = objmgr.GetArenaTeamById(group->ArenaTeamId);
324 if( at )
326 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating);
327 Player *plr = objmgr.GetPlayer(guid);
328 if( plr )
329 at->MemberLost(plr, group->OpponentsTeamRating);
330 else
331 at->OfflineMemberLost(guid, group->OpponentsTeamRating);
332 at->SaveToDB();
336 // remove group queue info if needed
337 if( group->Players.empty() )
339 m_QueuedGroups[queue_id][index].erase(group_itr);
340 delete group;
342 // if group wasn't empty, so it wasn't deleted, and player have left a rated
343 // queue -> everyone from the group should leave too
344 // don't remove recursively if already invited to bg!
345 else if( !group->IsInvitedToBGInstanceGUID && group->IsRated )
347 // remove next player, this is recursive
348 // first send removal information
349 if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
351 BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
352 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType);
353 uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
354 plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to
355 // queue->removeplayer, it causes bugs
356 WorldPacket data;
357 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
358 plr2->GetSession()->SendPacket(&data);
360 // then actually delete, this may delete the group as well!
361 RemovePlayer(group->Players.begin()->first, decreaseInvitedCount);
365 //Announce world message
366 void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue)
368 if(ginfo->ArenaType) //if Arena
370 if( sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated )
372 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
373 if(!bg)
374 return;
376 char const* bgName = bg->GetName();
377 if(isAddedToQueue)
378 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
379 else
380 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
383 else //if BG
385 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
387 Player *plr = objmgr.GetPlayer(playerGUID);
388 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
389 if(!bg || !plr)
390 return;
392 BGQueueIdBasedOnLevel queue_id = plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID());
393 char const* bgName = bg->GetName();
394 uint32 MinPlayers = bg->GetMinPlayersPerTeam();
395 uint32 qHorde = 0;
396 uint32 qAlliance = 0;
397 uint32 q_min_level = (queue_id + 1) * 10;
398 GroupsQueueType::const_iterator itr;
399 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
400 if( !(*itr)->IsInvitedToBGInstanceGUID )
401 qAlliance += (*itr)->Players.size();
402 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
403 if( !(*itr)->IsInvitedToBGInstanceGUID )
404 qHorde += (*itr)->Players.size();
406 // Show queue status to player only (when joining queue)
407 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY) )
409 ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
410 bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
412 // System message
413 else
415 sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
416 bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
422 bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
424 // set side if needed
425 if( side )
426 ginfo->Team = side;
428 if( !ginfo->IsInvitedToBGInstanceGUID )
430 // not yet invited
431 // set invitation
432 ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
433 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
434 BGQueueIdBasedOnLevel queue_id = bg->GetQueueId();
435 // loop through the players
436 for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
438 // get the player
439 Player* plr = objmgr.GetPlayer(itr->first);
440 // if offline, skip him, this should not happen - player is removed from queue when he logs out
441 if( !plr )
442 continue;
444 // invite the player
445 PlayerInvitedToBGUpdateAverageWaitTime(ginfo, queue_id);
446 ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME;
447 sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(), bg->GetTypeID(), ginfo->Team);
449 WorldPacket data;
451 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
453 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());
455 // send status packet
456 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType);
457 plr->GetSession()->SendPacket(&data);
459 return true;
462 return false;
465 // used to remove the Enter Battle window if the battle has already ended, but someone still has it
466 // (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event
467 void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
469 BGQueueIdBasedOnLevel queue_id = bg->GetQueueId();
470 uint32 bgInstanceId = bg->GetInstanceID();
471 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
472 GroupsQueueType::iterator itr, next;
473 for(uint32 i = 0; i < BG_QUEUE_GROUP_TYPES_COUNT; i++)
475 itr = m_QueuedGroups[queue_id][i].begin();
476 next = itr;
477 while (next != m_QueuedGroups[queue_id][i].end())
479 // must do this way, because the groupinfo will be deleted when all playerinfos are removed
480 itr = next;
481 ++next;
482 GroupQueueInfo * ginfo = (*itr);
483 // if group was invited to this bg instance, then remove all references
484 if( ginfo->IsInvitedToBGInstanceGUID == bgInstanceId )
486 // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop
487 uint32 to_remove = ginfo->Players.size();
488 for(uint32 j = 0; j < to_remove; j++)
490 // always remove the first one in the group
491 std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();
492 if( itr2 == ginfo->Players.end() )
494 sLog.outError("Empty Players in ginfo, this should never happen!");
495 return;
497 // get the player
498 Player * plr = objmgr.GetPlayer(itr2->first);
499 if( !plr )
501 sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");
502 continue;
505 // get the queueslot
506 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
507 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
509 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
510 // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
511 RemovePlayer(itr2->first, true);
512 WorldPacket data;
513 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
514 plr->GetSession()->SendPacket(&data);
523 This function is inviting players to already running battlegrounds
524 Invitation type is based on config file
525 large groups are disadvantageous, because they will be kicked first if invitation type = 1
527 void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id)
529 uint32 hordeFree = bg->GetFreeSlotsForTeam(HORDE);
530 uint32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE);
532 //iterator for iterating through bg queue
533 GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin();
534 //count of groups in queue - used to stop cycles
535 uint32 aliCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].size();
536 //index to queue which group is current
537 uint32 aliIndex = 0;
538 for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++)
539 ++Ali_itr;
540 //the same thing for horde
541 GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin();
542 uint32 hordeCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].size();
543 uint32 hordeIndex = 0;
544 for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++)
545 ++Horde_itr;
547 //if ofc like BG queue invitation is set in config, then we are happy
548 if (sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == 0)
549 return;
552 if we reached this code, then we have to solve NP - complete problem called Subset sum problem
553 So one solution is to check all possible invitation subgroups, or we can use these conditions:
554 1. Last time when BattleGroundQueue::Update was executed we invited all possible players - so there is only small possibility
555 that we will invite now whole queue, because only 1 change has been made to queues from the last BattleGroundQueue::Update call
556 2. Other thing we should consider is group order in queue
559 // At first we need to compare free space in bg and our selection pool
560 int32 diffAli = aliFree - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount();
561 int32 diffHorde = hordeFree - m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount();
562 while( abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0) )
564 //each cycle execution we need to kick at least 1 group
565 if( diffAli < diffHorde )
567 //kick alliance group, add to pool new group if needed
568 if( m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli) )
570 for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++)
571 ++Ali_itr;
573 //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break;
574 if( !m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() )
576 if( aliFree <= diffHorde + 1 )
577 break;
578 m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli);
581 else
583 //kick horde group, add to pool new group if needed
584 if( m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde) )
586 for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++)
587 ++Horde_itr;
589 if( !m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() )
591 if( hordeFree <= diffAli + 1 )
592 break;
593 m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde);
596 //count diffs after small update
597 diffAli = aliFree - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount();
598 diffHorde = hordeFree - m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount();
602 // this method checks if premade versus premade battleground is possible
603 // then after 30 mins (default) in queue it moves premade group to normal queue
604 // it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players
605 bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
607 //check match
608 if(!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
610 //start premade match
611 //if groups aren't invited
612 GroupsQueueType::const_iterator ali_group, horde_group;
613 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)
614 if( !(*ali_group)->IsInvitedToBGInstanceGUID )
615 break;
616 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)
617 if( !(*horde_group)->IsInvitedToBGInstanceGUID )
618 break;
620 if( ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end())
622 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
623 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
624 //add groups/players from normal queue to size of bigger group
625 uint32 maxPlayers = std::max(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
626 GroupsQueueType::const_iterator itr;
627 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
629 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
631 //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
632 if( !(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers) )
633 break;
636 //premade selection pools are set
637 return true;
640 // now check if we can move group from Premade queue to normal queue (timer has expired) or group size lowered!!
641 // this could be 2 cycles but i'm checking only first team in queue - it can cause problem -
642 // 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
643 // and when they click or after 80 seconds the queue info is removed from queue
644 uint32 time_before = getMSTime() - sWorld.getConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
645 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
647 if(!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
649 GroupsQueueType::iterator itr = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin();
650 if(!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam))
652 //we must insert group to normal queue and erase pointer from premade queue
653 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
654 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr);
658 //selection pools are not set
659 return false;
662 // this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
663 bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers)
665 GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
666 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
668 itr_team[i] = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
669 for(; itr_team[i] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i]))
671 if( !(*(itr_team[i]))->IsInvitedToBGInstanceGUID )
673 m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers);
674 if( m_SelectionPools[i].GetPlayerCount() >= minPlayers )
675 break;
679 //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
680 uint32 j = BG_TEAM_ALLIANCE;
681 if( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() )
682 j = BG_TEAM_HORDE;
683 if( sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != 0
684 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers )
686 //we will try to invite more groups to team with less players indexed by j
687 ++(itr_team[j]); //this will not cause a crash, because for cycle above reached break;
688 for(; itr_team[j] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
690 if( !(*(itr_team[j]))->IsInvitedToBGInstanceGUID )
691 if( !m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()) )
692 break;
694 // do not allow to start bg with more than 2 players more on 1 faction
695 if( abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2 )
696 return false;
698 //allow 1v0 if debug bg
699 if( sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) )
700 return true;
701 //return true if there are enough players in selection pools - enable to work .debug bg command correctly
702 return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers;
705 // this method will check if we can invite players to same faction skirmish match
706 bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam)
708 if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam )
709 return false;
710 uint32 teamIndex = BG_TEAM_ALLIANCE;
711 uint32 otherTeam = BG_TEAM_HORDE;
712 uint32 otherTeamId = HORDE;
713 if ( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam )
715 teamIndex = BG_TEAM_HORDE;
716 otherTeam = BG_TEAM_ALLIANCE;
717 otherTeamId = ALLIANCE;
719 //clear other team's selection
720 m_SelectionPools[otherTeam].Init();
721 //store last ginfo pointer
722 GroupQueueInfo* ginfo = m_SelectionPools[teamIndex].SelectedGroups.back();
723 //set itr_team to group that was added to selection pool latest
724 GroupsQueueType::iterator itr_team = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin();
725 for(; itr_team != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team)
726 if( ginfo == *itr_team )
727 break;
728 if( itr_team == m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end() )
729 return false;
730 GroupsQueueType::iterator itr_team2 = itr_team;
731 ++itr_team2;
732 //invite players to other selection pool
733 for(; itr_team2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team2)
735 //if selection pool is full then break;
736 if( !(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam) )
737 break;
739 if( m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam )
740 return false;
742 //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue
743 for(GroupsQueueType::iterator itr = m_SelectionPools[otherTeam].SelectedGroups.begin(); itr != m_SelectionPools[otherTeam].SelectedGroups.end(); ++itr)
745 //set correct team
746 (*itr)->Team = otherTeamId;
747 //add team to other queue
748 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + otherTeam].push_front(*itr);
749 //remove team from old queue
750 GroupsQueueType::iterator itr2 = itr_team;
751 ++itr2;
752 for(; itr2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2)
754 if( *itr2 == *itr )
756 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].erase(itr2);
757 break;
761 return true;
765 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
766 it must be called after fully adding the members of a group to ensure group joining
767 should be called from BattleGround::RemovePlayer function in some cases
769 void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated, uint32 arenaRating)
771 //if no players in queue - do nothing
772 if( m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
773 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() &&
774 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
775 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].empty() )
776 return;
778 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenaType);
780 //battleground with free slot for player should be always in the beggining of the queue
781 // maybe it would be better to create bgfreeslotqueue for each queue_id_based_on_level
782 BGFreeSlotQueueType::iterator itr, next;
783 for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
785 next = itr;
786 ++next;
787 // DO NOT allow queue manager to invite new player to arena
788 if( (*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueId() == queue_id &&
789 (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE )
791 BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
792 // and iterator is invalid
794 // clear selection pools
795 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
796 m_SelectionPools[BG_TEAM_HORDE].Init();
798 // call a function that does the job for us
799 FillPlayersToBG(bg, queue_id);
801 // now everything is set, invite players
802 for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.end(); ++itr)
803 InviteGroupToBG((*itr), bg, (*itr)->Team);
804 for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.end(); ++itr)
805 InviteGroupToBG((*itr), bg, (*itr)->Team);
807 if( !bg->HasFreeSlots() )
809 // remove BG from BGFreeSlotQueue
810 bg->RemoveFromBGFreeSlotQueue();
815 // finished iterating through the bgs with free slots, maybe we need to create a new bg
817 BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
818 if( !bg_template )
820 sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
821 return;
823 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
824 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
825 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
826 if( sBattleGroundMgr.isTesting() )
827 MinPlayersPerTeam = 1;
828 if( bg_template->isArena() )
830 if( sBattleGroundMgr.isArenaTesting() )
832 MaxPlayersPerTeam = 1;
833 MinPlayersPerTeam = 1;
835 else
837 //this switch can be much shorter
838 MaxPlayersPerTeam = arenaType;
839 MinPlayersPerTeam = arenaType;
840 /*switch(arenaType)
842 case ARENA_TYPE_2v2:
843 MaxPlayersPerTeam = 2;
844 MinPlayersPerTeam = 2;
845 break;
846 case ARENA_TYPE_3v3:
847 MaxPlayersPerTeam = 3;
848 MinPlayersPerTeam = 3;
849 break;
850 case ARENA_TYPE_5v5:
851 MaxPlayersPerTeam = 5;
852 MinPlayersPerTeam = 5;
853 break;
858 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
859 m_SelectionPools[BG_TEAM_HORDE].Init();
861 if( bg_template->isBattleGround() )
863 //check if there is premade against premade match
864 if( CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam) )
866 //create new battleground
867 BattleGround * bg2 = NULL;
868 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, 0, false)) )
870 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
871 return;
873 //invite those selection pools
874 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
875 for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++itr)
876 InviteGroupToBG((*itr), bg2, (*itr)->Team);
877 //start bg
878 bg2->StartBattleGround();
879 //clear structures
880 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
881 m_SelectionPools[BG_TEAM_HORDE].Init();
885 // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
886 if( !isRated )
888 // if there are enough players in pools, start new battleground or non rated arena
889 if( CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam)
890 || (bg_template->isArena() && CheckSkirmishForSameFaction(queue_id, MinPlayersPerTeam)) )
892 // we successfully created a pool
893 BattleGround * bg2 = NULL;
894 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, false)) )
896 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
897 return;
900 // invite those selection pools
901 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
902 for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++itr)
903 InviteGroupToBG((*itr), bg2, (*itr)->Team);
904 // start bg
905 bg2->StartBattleGround();
908 else if( bg_template->isArena() )
910 // found out the minimum and maximum ratings the newly added team should battle against
911 // arenaRating is the rating of the latest joined team, or 0
912 // 0 is on (automatic update call) and we must set it to team's with longest wait time
913 if ( !arenaRating )
915 GroupQueueInfo* front1 = NULL;
916 GroupQueueInfo* front2 = NULL;
917 if( !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() )
919 front1 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].front();
920 arenaRating = front1->ArenaTeamRating;
922 if( !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() )
924 front2 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].front();
925 arenaRating = front2->ArenaTeamRating;
927 if( front1 && front2 )
929 if( front1->JoinTime < front2->JoinTime )
930 arenaRating = front1->ArenaTeamRating;
932 else if( !front1 && !front2 )
933 return; //queues are empty
936 //set rating range
937 uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
938 uint32 arenaMaxRating = arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
939 // if max rating difference is set and the time past since server startup is greater than the rating discard time
940 // (after what time the ratings aren't taken into account when making teams) then
941 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
942 // else leave the discard time on 0, this way all ratings will be discarded
943 uint32 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
945 // we need to find 2 teams which will play next game
947 GroupsQueueType::iterator itr_team[BG_TEAMS_COUNT];
949 //optimalization : --- we dont need to use selection_pools - each update we select max 2 groups
951 for(uint32 i = BG_QUEUE_PREMADE_ALLIANCE; i < BG_QUEUE_NORMAL_ALLIANCE; i++)
953 // take the group that joined first
954 itr_team[i] = m_QueuedGroups[queue_id][i].begin();
955 for(; itr_team[i] != m_QueuedGroups[queue_id][i].end(); ++(itr_team[i]))
957 // if group match conditions, then add it to pool
958 if( !(*itr_team[i])->IsInvitedToBGInstanceGUID
959 && (((*itr_team[i])->ArenaTeamRating >= arenaMinRating && (*itr_team[i])->ArenaTeamRating <= arenaMaxRating)
960 || (*itr_team[i])->JoinTime < discardTime) )
962 m_SelectionPools[i].AddGroup((*itr_team[i]), MaxPlayersPerTeam);
963 // break for cycle to be able to start selecting another group from same faction queue
964 break;
968 // now we are done if we have 2 groups - ali vs horde!
969 // if we don't have, we must try to continue search in same queue
970 // tmp variables are correctly set
971 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue
972 if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() )
974 itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE];
975 ++itr_team[BG_TEAM_ALLIANCE];
976 for(; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE]))
978 if( !(*itr_team[BG_TEAM_ALLIANCE])->IsInvitedToBGInstanceGUID
979 && (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
980 || (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime) )
982 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*itr_team[BG_TEAM_ALLIANCE]), MaxPlayersPerTeam);
983 break;
987 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue
988 if( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() )
990 itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE];
991 ++itr_team[BG_TEAM_HORDE];
992 for(; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE]))
994 if( !(*itr_team[BG_TEAM_HORDE])->IsInvitedToBGInstanceGUID
995 && (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating)
996 || (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime) )
998 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*itr_team[BG_TEAM_HORDE]), MaxPlayersPerTeam);
999 break;
1004 //if we have 2 teams, then start new arena and invite players!
1005 if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() )
1007 BattleGround* arena = NULL;
1008 if( !(arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, true)) )
1010 sLog.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
1011 return;
1014 (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating;
1015 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating);
1016 (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating;
1017 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating);
1018 // 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
1019 if( (*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE )
1021 // add to alliance queue
1022 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE]));
1023 // erase from horde queue
1024 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]);
1025 itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
1027 if( (*(itr_team[BG_TEAM_HORDE]))->Team != HORDE )
1029 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE]));
1030 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]);
1031 itr_team[BG_TEAM_HORDE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin();
1034 InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE);
1035 InviteGroupToBG(*(itr_team[BG_TEAM_HORDE]), arena, HORDE);
1037 sLog.outDebug("Starting rated arena match!");
1039 arena->StartBattleGround();
1044 /*********************************************************/
1045 /*** BATTLEGROUND QUEUE EVENTS ***/
1046 /*********************************************************/
1048 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1050 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
1052 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1053 if (!plr)
1054 return true;
1056 // Player can be in another BG queue and must be removed in normal way in any case
1058 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1059 if (!bg)
1060 return true;
1062 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1063 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1064 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1066 // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
1067 BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
1068 BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
1069 if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1071 WorldPacket data;
1072 //here must be remaining time
1073 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, qItr->second.GroupInfo->ArenaType);
1074 plr->GetSession()->SendPacket(&data);
1077 return true; //event will be deleted
1080 void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
1082 //this should not be called
1083 sLog.outError("Battleground invite event ABORTED!");
1086 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1088 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
1089 if (!plr)
1090 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1091 return true;
1093 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1094 if (!bg)
1095 return true;
1097 sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
1099 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1100 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1101 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1103 // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
1104 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
1105 BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid);
1106 if (qMapItr != qpMap.end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1108 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
1109 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
1110 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bg->GetTypeID(), bg->GetQueueId());
1111 WorldPacket data;
1112 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
1113 plr->GetSession()->SendPacket(&data);
1116 else
1117 sLog.outDebug("Battleground: Player was already removed from queue");
1119 //event will be deleted
1120 return true;
1123 void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
1125 //this should not be called
1126 sLog.outError("Battleground remove event ABORTED!");
1129 /*********************************************************/
1130 /*** BATTLEGROUND MANAGER ***/
1131 /*********************************************************/
1133 BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
1135 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1136 m_BattleGrounds[i].clear();
1137 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1138 m_Testing=false;
1141 BattleGroundMgr::~BattleGroundMgr()
1143 DeleteAllBattleGrounds();
1146 void BattleGroundMgr::DeleteAllBattleGrounds()
1148 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1150 for(BattleGroundSet::iterator itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end();)
1152 BattleGround * bg = itr->second;
1153 m_BattleGrounds[i].erase(itr++);
1154 if(!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
1155 m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
1156 delete bg;
1160 // destroy template battlegrounds that listed only in queues (other already terminated)
1161 for(uint32 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId)
1163 // ~BattleGround call unregistring BG from queue
1164 while(!BGFreeSlotQueue[bgTypeId].empty())
1165 delete BGFreeSlotQueue[bgTypeId].front();
1169 // used to update running battlegrounds, and delete finished ones
1170 void BattleGroundMgr::Update(uint32 diff)
1172 BattleGroundSet::iterator itr, next;
1173 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1175 itr = m_BattleGrounds[i].begin();
1176 // skip updating battleground template
1177 if( itr != m_BattleGrounds[i].end() )
1178 ++itr;
1179 for(; itr != m_BattleGrounds[i].end(); itr = next)
1181 next = itr;
1182 ++next;
1183 itr->second->Update(diff);
1184 // use the SetDeleteThis variable
1185 // direct deletion caused crashes
1186 if(itr->second->m_SetDeleteThis)
1188 BattleGround * bg = itr->second;
1189 m_BattleGrounds[i].erase(itr);
1190 if(!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
1191 m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
1192 delete bg;
1196 // if rating difference counts, maybe force-update queues
1197 if(sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER))
1199 // it's time to force update
1200 if(m_NextRatingDiscardUpdate < diff)
1202 // forced update for level 70 rated arenas
1203 sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
1204 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_2v2, true, 0);
1205 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_2v2, true, 0);
1206 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_3v3, true, 0);
1207 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_3v3, true, 0);
1208 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_5v5, true, 0);
1209 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_5v5, true, 0);
1210 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1212 else
1213 m_NextRatingDiscardUpdate -= diff;
1215 if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1217 if(m_AutoDistributionTimeChecker < diff)
1219 if(sWorld.GetGameTime() > m_NextAutoDistributionTime)
1221 DistributeArenaPoints();
1222 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1223 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"I64FMTD"'", m_NextAutoDistributionTime);
1225 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1227 else
1228 m_AutoDistributionTimeChecker -= diff;
1232 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype)
1234 // we can be in 3 queues in same time...
1235 if(StatusID == 0)
1237 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
1238 *data << uint32(QueueSlot); // queue id (0...2)
1239 *data << uint64(0);
1240 return;
1243 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
1244 *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1245 // uint64 in client
1246 *data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1247 *data << uint32(bg->GetClientInstanceID());
1248 // alliance/horde for BG and skirmish/rated for Arenas
1249 // following displays the minimap-icon 0 = faction icon 1 = arenaicon
1250 *data << uint8(bg->isRated());
1251 /* *data << uint8(arenatype ? arenatype : bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas // NOT PROPER VALUE IF ARENA ISN'T RUNNING YET!!!!
1252 switch(bg->GetTypeID()) // value depends on bg id
1254 case BATTLEGROUND_AV:
1255 *data << uint8(1);
1256 break;
1257 case BATTLEGROUND_WS:
1258 *data << uint8(2);
1259 break;
1260 case BATTLEGROUND_AB:
1261 *data << uint8(3);
1262 break;
1263 case BATTLEGROUND_NA:
1264 *data << uint8(4);
1265 break;
1266 case BATTLEGROUND_BE:
1267 *data << uint8(5);
1268 break;
1269 case BATTLEGROUND_AA:
1270 *data << uint8(6);
1271 break;
1272 case BATTLEGROUND_EY:
1273 *data << uint8(7);
1274 break;
1275 case BATTLEGROUND_RL:
1276 *data << uint8(8);
1277 break;
1278 case BATTLEGROUND_SA:
1279 *data << uint8(9);
1280 break;
1281 case BATTLEGROUND_DS:
1282 *data << uint8(10);
1283 break;
1284 case BATTLEGROUND_RV:
1285 *data << uint8(11);
1286 break;
1287 default: // unknown
1288 *data << uint8(0);
1289 break;
1292 if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1293 *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1294 else
1295 *data << uint32(bg->GetTypeID()); // BG id from DBC
1297 *data << uint16(0x1F90); // unk value 8080
1298 *data << uint32(bg->GetInstanceID()); // instance id
1300 *data << uint8(bg->isArena()); // minimap-icon 0=faction 1=arena
1302 *data << uint32(StatusID); // status
1303 switch(StatusID)
1305 case STATUS_WAIT_QUEUE: // status_in_queue
1306 *data << uint32(Time1); // average wait time, milliseconds
1307 *data << uint32(Time2); // time in queue, updated every minute!, milliseconds
1308 break;
1309 case STATUS_WAIT_JOIN: // status_invite
1310 *data << uint32(bg->GetMapId()); // map id
1311 *data << uint32(Time1); // time to remove from queue, milliseconds
1312 break;
1313 case STATUS_IN_PROGRESS: // status_in_progress
1314 *data << uint32(bg->GetMapId()); // map id
1315 *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
1316 *data << uint32(Time2); // time from bg start, milliseconds
1317 *data << uint8(0x1); // unk sometimes 0x0!
1318 break;
1319 default:
1320 sLog.outError("Unknown BG status!");
1321 break;
1325 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1327 uint8 type = (bg->isArena() ? 1 : 0);
1328 // last check on 3.0.3
1329 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1330 *data << uint8(type); // type (battleground=0/arena=1)
1332 if(type) // arena
1334 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1335 for(int i = 1; i >= 0; --i)
1337 *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
1338 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1339 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1341 for(int i = 1; i >= 0; --i)
1343 uint32 at_id = bg->m_ArenaTeamIds[i];
1344 ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
1345 if(at)
1346 *data << at->GetName();
1347 else
1348 *data << (uint8)0;
1352 if(bg->GetStatus() != STATUS_WAIT_LEAVE)
1354 *data << uint8(0); // bg not ended
1356 else
1358 *data << uint8(1); // bg ended
1359 *data << uint8(bg->GetWinner()); // who win
1362 *data << (int32)(bg->GetPlayerScoresSize());
1364 for(std::map<uint64, BattleGroundScore*>::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1366 *data << (uint64)itr->first;
1367 *data << (int32)itr->second->KillingBlows;
1368 if(type == 0)
1370 *data << (int32)itr->second->HonorableKills;
1371 *data << (int32)itr->second->Deaths;
1372 *data << (int32)(itr->second->BonusHonor);
1374 else
1376 Player *plr = objmgr.GetPlayer(itr->first);
1377 uint32 team = bg->GetPlayerTeam(itr->first);
1378 if(!team && plr)
1379 team = plr->GetTeam();
1380 if( ( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ) )
1381 *data << uint8(1);
1382 else
1383 *data << uint8(0);
1385 *data << (int32)itr->second->DamageDone; // damage done
1386 *data << (int32)itr->second->HealingDone; // healing done
1387 switch(bg->GetTypeID()) // battleground specific things
1389 case BATTLEGROUND_AV:
1390 *data << (uint32)0x00000005; // count of next fields
1391 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1392 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1393 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1394 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1395 *data << (uint32)((BattleGroundAVScore*)itr->second)->MinesCaptured; // MinesCaptured
1396 break;
1397 case BATTLEGROUND_WS:
1398 *data << (uint32)0x00000002; // count of next fields
1399 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1400 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1401 break;
1402 case BATTLEGROUND_AB:
1403 *data << (uint32)0x00000002; // count of next fields
1404 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1405 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1406 break;
1407 case BATTLEGROUND_EY:
1408 *data << (uint32)0x00000001; // count of next fields
1409 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1410 break;
1411 case BATTLEGROUND_NA:
1412 case BATTLEGROUND_BE:
1413 case BATTLEGROUND_AA:
1414 case BATTLEGROUND_RL:
1415 case BATTLEGROUND_SA: // wotlk
1416 case BATTLEGROUND_DS: // wotlk
1417 case BATTLEGROUND_RV: // wotlk
1418 *data << (int32)0; // 0
1419 break;
1420 default:
1421 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1422 *data << (int32)0;
1423 break;
1428 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
1430 /*bgTypeId is:
1431 0 - Your group has joined a battleground queue, but you are not eligible
1432 1 - Your group has joined the queue for AV
1433 2 - Your group has joined the queue for WS
1434 3 - Your group has joined the queue for AB
1435 4 - Your group has joined the queue for NA
1436 5 - Your group has joined the queue for BE Arena
1437 6 - Your group has joined the queue for All Arenas
1438 7 - Your group has joined the queue for EotS*/
1439 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1440 *data << uint32(bgTypeId);
1443 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1445 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1446 *data << uint32(field);
1447 *data << uint32(value);
1450 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1452 data->Initialize(SMSG_PLAY_SOUND, 4);
1453 *data << uint32(soundid);
1456 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid)
1458 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1459 *data << uint64(guid);
1462 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1464 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1465 *data << uint64(plr->GetGUID());
1468 void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, BattleGroundTypeId bgTypeId, uint32 team)
1470 // set invited player counters:
1471 BattleGround* bg = GetBattleGround(bgInstanceGUID, bgTypeId);
1472 if(!bg)
1473 return;
1474 bg->IncreaseInvitedCount(team);
1476 plr->SetInviteForBattleGroundQueueType(BGQueueTypeId(bg->GetTypeID(),bg->GetArenaType()), bgInstanceGUID);
1478 // set the arena teams for rated matches
1479 if(bg->isArena() && bg->isRated())
1481 switch(bg->GetArenaType())
1483 case ARENA_TYPE_2v2:
1484 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));
1485 break;
1486 case ARENA_TYPE_3v3:
1487 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));
1488 break;
1489 case ARENA_TYPE_5v5:
1490 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));
1491 break;
1492 default:
1493 break;
1497 // create invite events:
1498 //add events to player's counters ---- this is not good way - there should be something like global event processor, where we should add those events
1499 BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID, bgTypeId);
1500 plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME));
1501 BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, bgTypeId, team);
1502 plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
1505 BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
1507 //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from
1508 //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
1509 BattleGround* bg = GetBattleGroundTemplate(bgTypeId);
1510 if( !bg )
1511 return NULL;
1513 if(bg->isArena())
1514 return GetBattleGround(instanceId, bgTypeId);
1516 for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr)
1518 if(itr->second->GetClientInstanceID() == instanceId)
1519 return itr->second;
1521 return NULL;
1524 BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
1526 //search if needed
1527 BattleGroundSet::iterator itr;
1528 if( bgTypeId == BATTLEGROUND_TYPE_NONE)
1530 for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1532 itr = m_BattleGrounds[i].find(InstanceID);
1533 if( itr != m_BattleGrounds[i].end() )
1534 return itr->second;
1536 return NULL;
1538 itr = m_BattleGrounds[bgTypeId].find(InstanceID);
1539 return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL );
1542 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
1544 //map is sorted and we can be sure that lowest instance id has only BG template
1545 return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second;
1548 uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
1550 if( IsArenaType(bgTypeId) )
1551 return 0; //arenas don't have client-instanceids
1553 // we create here an instanceid, which is just for
1554 // displaying this to the client and without any other use..
1555 // the client-instanceIds are unique for each battleground-type
1556 // the instance-id just needs to be as low as possible, beginning with 1
1557 // the following works, because std::set is default ordered with "<"
1558 // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
1559 uint32 lastId = 0;
1560 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();)
1562 if( (++lastId) != *itr) //if there is a gap between the ids, we will break..
1563 break;
1564 lastId = *itr;
1566 m_ClientBattleGroundIds[bgTypeId][queue_id].insert(lastId + 1);
1567 return lastId + 1;
1570 // create a new battleground that will really be used to play
1571 BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated)
1573 // get the template BG
1574 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1575 if(!bg_template)
1577 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1578 return NULL;
1581 //for arenas there is random map used
1582 if(bg_template->isArena())
1584 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
1585 uint32 arena_num = urand(0,2);
1586 bgTypeId = arenas[arena_num];
1587 bg_template = GetBattleGroundTemplate(bgTypeId);
1588 if(!bg_template)
1590 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1591 return NULL;
1595 BattleGround *bg = NULL;
1596 // create a copy of the BG template
1597 switch(bgTypeId)
1599 case BATTLEGROUND_AV:
1600 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1601 break;
1602 case BATTLEGROUND_WS:
1603 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1604 break;
1605 case BATTLEGROUND_AB:
1606 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1607 break;
1608 case BATTLEGROUND_NA:
1609 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1610 break;
1611 case BATTLEGROUND_BE:
1612 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1613 break;
1614 case BATTLEGROUND_AA:
1615 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1616 break;
1617 case BATTLEGROUND_EY:
1618 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1619 break;
1620 case BATTLEGROUND_RL:
1621 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1622 break;
1623 case BATTLEGROUND_SA:
1624 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1625 break;
1626 case BATTLEGROUND_DS:
1627 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1628 break;
1629 case BATTLEGROUND_RV:
1630 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1631 break;
1632 default:
1633 //error, but it is handled few lines above
1634 return 0;
1637 // generate a new instance id
1638 bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
1639 bg->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId, queue_id));
1641 // reset the new bg (set status to status_wait_queue from status_none)
1642 bg->Reset();
1644 // start the joining of the bg
1645 bg->SetStatus(STATUS_WAIT_JOIN);
1646 bg->SetQueueId(queue_id);
1647 bg->SetArenaType(arenaType);
1648 bg->SetRated(isRated);
1650 // add BG to free slot queue
1651 bg->AddToBGFreeSlotQueue();
1653 // add bg to update list
1654 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1656 return bg;
1659 // used to create the BG templates
1660 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)
1662 // Create the BG
1663 BattleGround *bg = NULL;
1664 switch(bgTypeId)
1666 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1667 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1668 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1669 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1670 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1671 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1672 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1673 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1674 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1675 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1676 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1677 default:bg = new BattleGround; break; // placeholder for non implemented BG
1680 bg->SetMapId(MapID);
1681 bg->SetTypeID(bgTypeId);
1682 bg->SetInstanceID(0);
1683 bg->SetArenaorBGType(IsArena);
1684 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1685 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1686 bg->SetMinPlayers(MinPlayersPerTeam * 2);
1687 bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
1688 bg->SetName(BattleGroundName);
1689 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1690 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1691 bg->SetLevelRange(LevelMin, LevelMax);
1693 // add bg to update list
1694 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1696 // return some not-null value, bgTypeId is good enough for me
1697 return bgTypeId;
1700 void BattleGroundMgr::CreateInitialBattleGrounds()
1702 float AStartLoc[4];
1703 float HStartLoc[4];
1704 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1705 BattlemasterListEntry const *bl;
1706 WorldSafeLocsEntry const *start;
1707 bool IsArena;
1709 uint32 count = 0;
1711 // 0 1 2 3 4 5 6 7 8
1712 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1714 if(!result)
1716 barGoLink bar(1);
1718 bar.step();
1720 sLog.outString();
1721 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1722 return;
1725 barGoLink bar(result->GetRowCount());
1729 Field *fields = result->Fetch();
1730 bar.step();
1732 uint32 bgTypeID_ = fields[0].GetUInt32();
1734 // can be overwrite by values from DB
1735 bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
1736 if(!bl)
1738 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
1739 continue;
1742 BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
1744 IsArena = (bl->type == TYPE_ARENA);
1745 MinPlayersPerTeam = fields[1].GetUInt32();
1746 MaxPlayersPerTeam = fields[2].GetUInt32();
1747 MinLvl = fields[3].GetUInt32();
1748 MaxLvl = fields[4].GetUInt32();
1749 //check values from DB
1750 if( MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam )
1752 MaxPlayersPerTeam = bl->maxplayersperteam;
1753 MinPlayersPerTeam = bl->maxplayersperteam / 2;
1755 if( MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl )
1757 MinLvl = bl->minlvl;
1758 MaxLvl = bl->maxlvl;
1761 start1 = fields[5].GetUInt32();
1763 start = sWorldSafeLocsStore.LookupEntry(start1);
1764 if(start)
1766 AStartLoc[0] = start->x;
1767 AStartLoc[1] = start->y;
1768 AStartLoc[2] = start->z;
1769 AStartLoc[3] = fields[6].GetFloat();
1771 else if(bgTypeID == BATTLEGROUND_AA)
1773 AStartLoc[0] = 0;
1774 AStartLoc[1] = 0;
1775 AStartLoc[2] = 0;
1776 AStartLoc[3] = fields[6].GetFloat();
1778 else
1780 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
1781 continue;
1784 start2 = fields[7].GetUInt32();
1786 start = sWorldSafeLocsStore.LookupEntry(start2);
1787 if(start)
1789 HStartLoc[0] = start->x;
1790 HStartLoc[1] = start->y;
1791 HStartLoc[2] = start->z;
1792 HStartLoc[3] = fields[8].GetFloat();
1794 else if(bgTypeID == BATTLEGROUND_AA)
1796 HStartLoc[0] = 0;
1797 HStartLoc[1] = 0;
1798 HStartLoc[2] = 0;
1799 HStartLoc[3] = fields[8].GetFloat();
1801 else
1803 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
1804 continue;
1807 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1808 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]))
1809 continue;
1811 ++count;
1812 } while (result->NextRow());
1814 delete result;
1816 sLog.outString();
1817 sLog.outString( ">> Loaded %u battlegrounds", count );
1820 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1822 if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1824 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1825 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1826 if(!result)
1828 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1829 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1830 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"I64FMTD"')", m_NextAutoDistributionTime);
1832 else
1834 m_NextAutoDistributionTime = (*result)[0].GetUInt64();
1835 delete result;
1837 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1841 void BattleGroundMgr::DistributeArenaPoints()
1843 // used to distribute arena points based on last week's stats
1844 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
1846 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
1848 //temporary structure for storing maximum points to add values for all players
1849 std::map<uint32, uint32> PlayerPoints;
1851 //at first update all points for all team members
1852 for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
1854 if(ArenaTeam * at = team_itr->second)
1856 at->UpdateArenaPointsHelper(PlayerPoints);
1860 //cycle that gives points to all players
1861 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1863 //update to database
1864 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
1865 //add points if player is online
1866 Player* pl = objmgr.GetPlayer(plr_itr->first);
1867 if (pl)
1868 pl->ModifyArenaPoints(plr_itr->second);
1871 PlayerPoints.clear();
1873 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
1875 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
1876 for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
1878 if(ArenaTeam * at = titr->second)
1880 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1881 at->SaveToDB(); // save changes
1882 at->NotifyStatsChanged(); // notify the players of the changes
1886 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
1888 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
1891 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId)
1893 uint32 PlayerLevel = 10;
1895 if(plr)
1896 PlayerLevel = plr->getLevel();
1898 data->Initialize(SMSG_BATTLEFIELD_LIST);
1899 *data << uint64(guid); // battlemaster guid
1900 *data << uint32(bgTypeId); // battleground id
1901 if(bgTypeId == BATTLEGROUND_AA) // arena
1903 *data << uint8(5); // unk
1904 *data << uint32(0); // unk
1906 else // battleground
1908 *data << uint8(0x00); // unk
1910 size_t count_pos = data->wpos();
1911 uint32 count = 0;
1912 *data << uint32(0x00); // number of bg instances
1914 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(bgTypeId);
1915 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();++itr)
1917 *data << uint32(*itr);
1918 ++count;
1920 data->put<uint32>( count_pos , count);
1924 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId)
1926 BattleGround *bg = GetBattleGround(instanceId, bgTypeId);
1927 if(bg)
1929 uint32 mapid = bg->GetMapId();
1930 float x, y, z, O;
1931 uint32 team = pl->GetBGTeam();
1932 if(team==0)
1933 team = pl->GetTeam();
1934 bg->GetTeamStartLoc(team, x, y, z, O);
1936 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1937 pl->TeleportTo(mapid, x, y, z, O);
1939 else
1941 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1945 void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid)
1947 WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
1948 uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
1949 if(time_ == uint32(-1))
1950 time_ = 0;
1951 data << guid << time_;
1952 pl->GetSession()->SendPacket(&data);
1955 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
1957 return ( bgTypeId == BATTLEGROUND_AA ||
1958 bgTypeId == BATTLEGROUND_BE ||
1959 bgTypeId == BATTLEGROUND_NA ||
1960 bgTypeId == BATTLEGROUND_RL );
1963 BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
1965 switch(bgTypeId)
1967 case BATTLEGROUND_WS:
1968 return BATTLEGROUND_QUEUE_WS;
1969 case BATTLEGROUND_AB:
1970 return BATTLEGROUND_QUEUE_AB;
1971 case BATTLEGROUND_AV:
1972 return BATTLEGROUND_QUEUE_AV;
1973 case BATTLEGROUND_EY:
1974 return BATTLEGROUND_QUEUE_EY;
1975 case BATTLEGROUND_SA:
1976 return BATTLEGROUND_QUEUE_SA;
1977 case BATTLEGROUND_AA:
1978 case BATTLEGROUND_NA:
1979 case BATTLEGROUND_RL:
1980 case BATTLEGROUND_BE:
1981 case BATTLEGROUND_DS:
1982 case BATTLEGROUND_RV:
1983 switch(arenaType)
1985 case ARENA_TYPE_2v2:
1986 return BATTLEGROUND_QUEUE_2v2;
1987 case ARENA_TYPE_3v3:
1988 return BATTLEGROUND_QUEUE_3v3;
1989 case ARENA_TYPE_5v5:
1990 return BATTLEGROUND_QUEUE_5v5;
1991 default:
1992 return BATTLEGROUND_QUEUE_NONE;
1994 default:
1995 return BATTLEGROUND_QUEUE_NONE;
1999 BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId)
2001 switch(bgQueueTypeId)
2003 case BATTLEGROUND_QUEUE_WS:
2004 return BATTLEGROUND_WS;
2005 case BATTLEGROUND_QUEUE_AB:
2006 return BATTLEGROUND_AB;
2007 case BATTLEGROUND_QUEUE_AV:
2008 return BATTLEGROUND_AV;
2009 case BATTLEGROUND_QUEUE_EY:
2010 return BATTLEGROUND_EY;
2011 case BATTLEGROUND_QUEUE_SA:
2012 return BATTLEGROUND_SA;
2013 case BATTLEGROUND_QUEUE_2v2:
2014 case BATTLEGROUND_QUEUE_3v3:
2015 case BATTLEGROUND_QUEUE_5v5:
2016 return BATTLEGROUND_AA;
2017 default:
2018 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
2022 uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId)
2024 switch(bgQueueTypeId)
2026 case BATTLEGROUND_QUEUE_2v2:
2027 return ARENA_TYPE_2v2;
2028 case BATTLEGROUND_QUEUE_3v3:
2029 return ARENA_TYPE_3v3;
2030 case BATTLEGROUND_QUEUE_5v5:
2031 return ARENA_TYPE_5v5;
2032 default:
2033 return 0;
2037 void BattleGroundMgr::ToggleTesting()
2039 m_Testing = !m_Testing;
2040 if(m_Testing)
2041 sWorld.SendWorldText(LANG_DEBUG_BG_ON);
2042 else
2043 sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
2046 void BattleGroundMgr::ToggleArenaTesting()
2048 m_ArenaTesting = !m_ArenaTesting;
2049 if(m_ArenaTesting)
2050 sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
2051 else
2052 sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
2055 uint32 BattleGroundMgr::GetMaxRatingDifference() const
2057 // this is for stupid people who can't use brain and set max rating difference to 0
2058 uint32 diff = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
2059 if (diff == 0)
2060 diff = 5000;
2061 return diff;
2064 uint32 BattleGroundMgr::GetRatingDiscardTimer() const
2066 return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
2069 uint32 BattleGroundMgr::GetPrematureFinishTime() const
2071 return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
2074 void BattleGroundMgr::LoadBattleMastersEntry()
2076 mBattleMastersMap.clear(); // need for reload case
2078 QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
2080 uint32 count = 0;
2082 if( !result )
2084 barGoLink bar( 1 );
2085 bar.step();
2087 sLog.outString();
2088 sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
2089 return;
2092 barGoLink bar( result->GetRowCount() );
2096 ++count;
2097 bar.step();
2099 Field *fields = result->Fetch();
2101 uint32 entry = fields[0].GetUInt32();
2102 uint32 bgTypeId = fields[1].GetUInt32();
2103 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
2105 sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
2106 continue;
2109 mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
2111 } while( result->NextRow() );
2113 delete result;
2115 sLog.outString();
2116 sLog.outString( ">> Loaded %u battlemaster entries", count );