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
20 #include "SharedDefines.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"
38 #include "MapInstanced.h"
39 #include "ObjectMgr.h"
40 #include "ProgressBar.h"
42 #include "ArenaTeam.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
)
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();
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
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)
110 else if (!found
&& (*itr
)->Players
.size() >= (*groupToKick
)->Players
.size())
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)
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();
141 if (PlayerCount
< desiredCount
)
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();
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
172 if (!isRated
&& !isPremade
)
173 index
+= BG_TEAMS_COUNT
;
174 if (ginfo
->Team
== HORDE
)
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);
191 for(GroupReference
*itr
= grp
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
193 Player
*member
= itr
->getSource();
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
;
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
);
220 char const* bgName
= bg
->GetName();
221 uint32 MinPlayers
= bg
->GetMinPlayersPerTeam();
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);
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);
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
;
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
;
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
);
298 //if there aren't enough values return 0 - not available
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
));
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
345 //player can't be in queue without group, but just in case
348 sLog
.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid
));
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
);
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
);
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
);
387 at
->MemberLost(plr
, group
->OpponentsTeamRating
);
389 at
->OfflineMemberLost(guid
, group
->OpponentsTeamRating
);
394 // remove group queue info if needed
395 if (group
->Players
.empty())
397 m_QueuedGroups
[queue_id
][index
].erase(group_itr
);
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
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())
439 *ginfo
= *(qItr
->second
.GroupInfo
);
443 bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo
* ginfo
, BattleGround
* bg
, uint32 side
)
445 // set side if needed
449 if (!ginfo
->IsInvitedToBGInstanceGUID
)
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
)
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
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
));
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
);
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
521 for (; aliIndex
< aliCount
&& m_SelectionPools
[BG_TEAM_ALLIANCE
].AddGroup((*Ali_itr
), aliFree
); aliIndex
++)
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
++)
530 //if ofc like BG queue invitation is set in config, then we are happy
531 if (sWorld
.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE
) == 0)
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
++)
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)
561 m_SelectionPools
[BG_TEAM_HORDE
].KickGroup(diffHorde
- diffAli
);
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
++)
572 if (!m_SelectionPools
[BG_TEAM_HORDE
].GetPlayerCount())
574 if (hordeFree
<= diffAli
+ 1)
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
)
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
)
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
)
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
))
619 //premade selection pools are set
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
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
)
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())
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()))
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)
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()))
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
)
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
)
711 if (itr_team
== m_QueuedGroups
[queue_id
][BG_QUEUE_NORMAL_ALLIANCE
+ teamIndex
].end())
713 GroupsQueueType::iterator itr_team2
= itr_team
;
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
))
722 if (m_SelectionPools
[otherTeam
].GetPlayerCount() != minPlayersPerTeam
)
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
)
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
;
735 for(; itr2
!= m_QueuedGroups
[queue_id
][BG_QUEUE_NORMAL_ALLIANCE
+ teamIndex
].end(); ++itr2
)
739 m_QueuedGroups
[queue_id
][BG_QUEUE_NORMAL_ALLIANCE
+ teamIndex
].erase(itr2
);
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() )
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
)
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
);
802 sLog
.outError("Battleground: Update: bg template not found for %u", bgTypeId
);
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;
819 //this switch can be much shorter
820 MaxPlayersPerTeam
= arenaType
;
821 MinPlayersPerTeam
= arenaType
;
825 MaxPlayersPerTeam = 2;
826 MinPlayersPerTeam = 2;
829 MaxPlayersPerTeam = 3;
830 MinPlayersPerTeam = 3;
833 MaxPlayersPerTeam = 5;
834 MinPlayersPerTeam = 5;
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
);
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
);
860 bg2
->StartBattleGround();
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)
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
);
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
);
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
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
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
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
);
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
);
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!");
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)
1037 BattleGround
* bg
= sBattleGroundMgr
.GetBattleGround(m_BgInstanceGUID
, m_BgTypeId
);
1038 //if battleground ended and its instance deleted - do nothing
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
))
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*/)
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
);
1077 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
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());
1100 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, queueSlot
, STATUS_NONE
, 0, 0, 0);
1101 plr
->GetSession()->SendPacket(&data
);
1105 //event will be deleted
1109 void BGQueueRemoveEvent::Abort(uint64
/*e_time*/)
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
);
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());
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())
1164 for(; itr
!= m_BattleGrounds
[i
].end(); itr
= 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());
1182 // update scheduled queues
1183 if (!m_QueueUpdateScheduler
.empty())
1185 std::vector
<uint64
> scheduled
;
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();
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
);
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
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)
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
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
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
1271 case STATUS_WAIT_JOIN
: // status_invite
1272 *data
<< uint32(bg
->GetMapId()); // map id
1273 *data
<< uint32(Time1
); // time to remove from queue, milliseconds
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!
1282 sLog
.outError("Unknown BG status!");
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)
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
);
1309 *data
<< at
->GetName();
1315 if (bg
->GetStatus() != STATUS_WAIT_LEAVE
)
1317 *data
<< uint8(0); // bg not ended
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
;
1333 *data
<< (int32
)itr
->second
->HonorableKills
;
1334 *data
<< (int32
)itr
->second
->Deaths
;
1335 *data
<< (int32
)(itr
->second
->BonusHonor
);
1339 Player
*plr
= sObjectMgr
.GetPlayer(itr
->first
);
1340 uint32 team
= bg
->GetPlayerTeam(itr
->first
);
1342 team
= plr
->GetTeam();
1343 if (( bg
->GetWinner()==0 && team
== ALLIANCE
) || ( bg
->GetWinner()==1 && team
==HORDE
))
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
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
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
1370 case BATTLEGROUND_EY
:
1371 *data
<< (uint32
)0x00000001; // count of next fields
1372 *data
<< (uint32
)((BattleGroundEYScore
*)itr
->second
)->FlagCaptures
; // flag captures
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
1386 sLog
.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg
->GetTypeID());
1393 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket
*data
, BattleGroundTypeId bgTypeId
)
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
);
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
)
1452 BattleGround
* BattleGroundMgr::GetBattleGround(uint32 InstanceID
, BattleGroundTypeId bgTypeId
)
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())
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
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..
1494 m_ClientBattleGroundIds
[bgTypeId
][queue_id
].insert(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
);
1505 sLog
.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId
);
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
);
1518 sLog
.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId
);
1523 BattleGround
*bg
= NULL
;
1524 // create a copy of the BG template
1527 case BATTLEGROUND_AV
:
1528 bg
= new BattleGroundAV(*(BattleGroundAV
*)bg_template
);
1530 case BATTLEGROUND_WS
:
1531 bg
= new BattleGroundWS(*(BattleGroundWS
*)bg_template
);
1533 case BATTLEGROUND_AB
:
1534 bg
= new BattleGroundAB(*(BattleGroundAB
*)bg_template
);
1536 case BATTLEGROUND_NA
:
1537 bg
= new BattleGroundNA(*(BattleGroundNA
*)bg_template
);
1539 case BATTLEGROUND_BE
:
1540 bg
= new BattleGroundBE(*(BattleGroundBE
*)bg_template
);
1542 case BATTLEGROUND_AA
:
1543 bg
= new BattleGroundAA(*(BattleGroundAA
*)bg_template
);
1545 case BATTLEGROUND_EY
:
1546 bg
= new BattleGroundEY(*(BattleGroundEY
*)bg_template
);
1548 case BATTLEGROUND_RL
:
1549 bg
= new BattleGroundRL(*(BattleGroundRL
*)bg_template
);
1551 case BATTLEGROUND_SA
:
1552 bg
= new BattleGroundSA(*(BattleGroundSA
*)bg_template
);
1554 case BATTLEGROUND_DS
:
1555 bg
= new BattleGroundDS(*(BattleGroundDS
*)bg_template
);
1557 case BATTLEGROUND_RV
:
1558 bg
= new BattleGroundRV(*(BattleGroundRV
*)bg_template
);
1560 case BATTLEGROUND_IC
:
1561 bg
= new BattleGroundIC(*(BattleGroundIC
*)bg_template
);
1563 case BATTLEGROUND_ABG
:
1564 bg
= new BattleGroundABG(*(BattleGroundABG
*)bg_template
);
1567 //error, but it is handled few lines above
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)
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
);
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
)
1591 BattleGround
*bg
= NULL
;
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
1630 void BattleGroundMgr::CreateInitialBattleGrounds()
1634 uint32 MaxPlayersPerTeam
, MinPlayersPerTeam
, MinLvl
, MaxLvl
, start1
, start2
;
1635 BattlemasterListEntry
const *bl
;
1636 WorldSafeLocsEntry
const *start
;
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");
1651 sLog
.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1655 barGoLink
bar(result
->GetRowCount());
1659 Field
*fields
= result
->Fetch();
1662 uint32 bgTypeID_
= fields
[0].GetUInt32();
1664 // can be overwrite by values from DB
1665 bl
= sBattlemasterListStore
.LookupEntry(bgTypeID_
);
1668 sLog
.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_
);
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
)
1688 MinLvl
= 0;//bl->minlvl;
1689 MaxLvl
= 80;//bl->maxlvl;
1692 start1
= fields
[5].GetUInt32();
1694 start
= sWorldSafeLocsStore
.LookupEntry(start1
);
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
)
1707 AStartLoc
[3] = fields
[6].GetFloat();
1711 sLog
.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID
, start1
);
1715 start2
= fields
[7].GetUInt32();
1717 start
= sWorldSafeLocsStore
.LookupEntry(start2
);
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
)
1730 HStartLoc
[3] = fields
[8].GetFloat();
1734 sLog
.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID
, start2
);
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]))
1743 } while (result
->NextRow());
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");
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
));
1765 m_NextAutoDistributionTime
= time_t((*result
)[0].GetUInt64());
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
);
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
)
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();
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
);
1855 data
->put
<uint32
>( count_pos
, count
);
1859 void BattleGroundMgr::SendToBattleGround(Player
*pl
, uint32 instanceId
, BattleGroundTypeId bgTypeId
)
1861 BattleGround
*bg
= GetBattleGround(instanceId
, bgTypeId
);
1864 uint32 mapid
= bg
->GetMapId();
1866 uint32 team
= pl
->GetBGTeam();
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
);
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
)
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
:
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
;
1921 return BATTLEGROUND_QUEUE_NONE
;
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
;
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
;
1968 void BattleGroundMgr::ToggleTesting()
1970 m_Testing
= !m_Testing
;
1972 sWorld
.SendWorldText(LANG_DEBUG_BG_ON
);
1974 sWorld
.SendWorldText(LANG_DEBUG_BG_OFF
);
1977 void BattleGroundMgr::ToggleArenaTesting()
1979 m_ArenaTesting
= !m_ArenaTesting
;
1981 sWorld
.SendWorldText(LANG_DEBUG_ARENA_ON
);
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
;
1992 for (uint8 i
= 0; i
< m_QueueUpdateScheduler
.size(); i
++)
1994 if (m_QueueUpdateScheduler
[i
] == schedule_id
)
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
);
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" );
2037 sLog
.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
2041 barGoLink
bar( result
->GetRowCount() );
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
);
2058 mBattleMastersMap
[entry
] = BattleGroundTypeId(bgTypeId
);
2060 } while( result
->NextRow() );
2065 sLog
.outString( ">> Loaded %u battlemaster entries", count
);
2068 bool BattleGroundMgr::IsBGWeekend(BattleGroundTypeId 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
);
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
;
2097 QueryResult
*result
=
2099 WorldDatabase
.PQuery( "SELECT data.typ, data.guid1, data.ev1 AS ev1, data.ev2 AS ev2, data.map AS m, data.guid2, description.map, "
2101 "description.event1, description.event2, description.description "
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 "
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 "
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
2115 "SELECT data.typ, data.guid1, data.ev1, data.ev2, data.map, data.guid2, description.map, "
2116 "description.event1, description.event2, description.description "
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 "
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 "
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" );
2135 sLog
.outErrorDb(">> Loaded 0 battleground eventindexes.");
2139 barGoLink
bar(result
->GetRowCount());
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
);
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
);
2176 // we have an event which shouldn't exist
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
);
2186 m_GameObjectBattleEventIndexMap
[dbTableGuidLow
] = events
;
2188 m_CreatureBattleEventIndexMap
[dbTableGuidLow
] = events
;
2192 } while(result
->NextRow());
2195 sLog
.outString( ">> Loaded %u battleground eventindexes", count
);