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_BRACKETS
; ++j
)
61 m_SumOfWaitTimes
[i
][j
] = 0;
62 m_WaitTimeLastPlayer
[i
][j
] = 0;
63 for(uint32 k
= 0; k
< COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME
; ++k
)
64 m_WaitTimes
[i
][j
][k
] = 0;
69 BattleGroundQueue::~BattleGroundQueue()
71 m_QueuedPlayers
.clear();
72 for (int i
= 0; i
< MAX_BATTLEGROUND_BRACKETS
; ++i
)
74 for(uint32 j
= 0; j
< BG_QUEUE_GROUP_TYPES_COUNT
; ++j
)
76 for(GroupsQueueType::iterator itr
= m_QueuedGroups
[i
][j
].begin(); itr
!= m_QueuedGroups
[i
][j
].end(); ++itr
)
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
, PvPDifficultyEntry
const* backetEntry
, uint8 ArenaType
, bool isRated
, bool isPremade
, uint32 arenaRating
, uint32 arenateamid
)
153 BattleGroundBracketId bracketId
= backetEntry
->GetBracketId();
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, bracket_id : %u, index : %u", BgTypeId
, bracketId
, index
);
178 uint32 lastOnlineTime
= getMSTime();
180 //announce world (this don't need mutex)
181 if (isRated
&& sWorld
.getConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_ENABLE
))
183 sWorld
.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN
, ginfo
->ArenaType
, ginfo
->ArenaType
, ginfo
->ArenaTeamRating
);
186 //add players from group to ginfo
188 //ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock);
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
[bracketId
][index
].push_back(ginfo
);
214 //announce to world, this code needs mutex
215 if (!isRated
&& !isPremade
&& sWorld
.getConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE
))
217 if (BattleGround
* bg
= sBattleGroundMgr
.GetBattleGroundTemplate(ginfo
->BgTypeId
))
219 char const* bgName
= bg
->GetName();
220 uint32 MinPlayers
= bg
->GetMinPlayersPerTeam();
222 uint32 qAlliance
= 0;
223 uint32 q_min_level
= backetEntry
->minLevel
;
224 uint32 q_max_level
= backetEntry
->maxLevel
;
225 GroupsQueueType::const_iterator itr
;
226 for(itr
= m_QueuedGroups
[bracketId
][BG_QUEUE_NORMAL_ALLIANCE
].begin(); itr
!= m_QueuedGroups
[bracketId
][BG_QUEUE_NORMAL_ALLIANCE
].end(); ++itr
)
227 if (!(*itr
)->IsInvitedToBGInstanceGUID
)
228 qAlliance
+= (*itr
)->Players
.size();
229 for(itr
= m_QueuedGroups
[bracketId
][BG_QUEUE_NORMAL_HORDE
].begin(); itr
!= m_QueuedGroups
[bracketId
][BG_QUEUE_NORMAL_HORDE
].end(); ++itr
)
230 if (!(*itr
)->IsInvitedToBGInstanceGUID
)
231 qHorde
+= (*itr
)->Players
.size();
233 // Show queue status to player only (when joining queue)
234 if (sWorld
.getConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY
))
236 ChatHandler(leader
).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF
, bgName
, q_min_level
, q_max_level
,
237 qAlliance
, (MinPlayers
> qAlliance
) ? MinPlayers
- qAlliance
: (uint32
)0, qHorde
, (MinPlayers
> qHorde
) ? MinPlayers
- qHorde
: (uint32
)0);
242 sWorld
.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD
, bgName
, q_min_level
, q_max_level
,
243 qAlliance
, (MinPlayers
> qAlliance
) ? MinPlayers
- qAlliance
: (uint32
)0, qHorde
, (MinPlayers
> qHorde
) ? MinPlayers
- qHorde
: (uint32
)0);
253 void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo
* ginfo
, BattleGroundBracketId bracket_id
)
255 uint32 timeInQueue
= getMSTimeDiff(ginfo
->JoinTime
, getMSTime());
256 uint8 team_index
= BG_TEAM_ALLIANCE
; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
257 if (!ginfo
->ArenaType
)
259 if (ginfo
->Team
== HORDE
)
260 team_index
= BG_TEAM_HORDE
;
265 team_index
= BG_TEAM_HORDE
; //for rated arenas use BG_TEAM_HORDE
268 //store pointer to arrayindex of player that was added first
269 uint32
* lastPlayerAddedPointer
= &(m_WaitTimeLastPlayer
[team_index
][bracket_id
]);
270 //remove his time from sum
271 m_SumOfWaitTimes
[team_index
][bracket_id
] -= m_WaitTimes
[team_index
][bracket_id
][(*lastPlayerAddedPointer
)];
272 //set average time to new
273 m_WaitTimes
[team_index
][bracket_id
][(*lastPlayerAddedPointer
)] = timeInQueue
;
274 //add new time to sum
275 m_SumOfWaitTimes
[team_index
][bracket_id
] += timeInQueue
;
276 //set index of last player added to next one
277 (*lastPlayerAddedPointer
)++;
278 (*lastPlayerAddedPointer
) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME
;
281 uint32
BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo
* ginfo
, BattleGroundBracketId bracket_id
)
283 uint8 team_index
= BG_TEAM_ALLIANCE
; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
284 if (!ginfo
->ArenaType
)
286 if (ginfo
->Team
== HORDE
)
287 team_index
= BG_TEAM_HORDE
;
292 team_index
= BG_TEAM_HORDE
; //for rated arenas use BG_TEAM_HORDE
294 //check if there is enought values(we always add values > 0)
295 if (m_WaitTimes
[team_index
][bracket_id
][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME
- 1] )
296 return (m_SumOfWaitTimes
[team_index
][bracket_id
] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME
);
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 bracket_id
= -1; // signed for proper for-loop finish
309 QueuedPlayersMap::iterator itr
;
311 //remove player from map, if he's there
312 itr
= m_QueuedPlayers
.find(guid
);
313 if (itr
== m_QueuedPlayers
.end())
315 sLog
.outError("BattleGroundQueue: couldn't find player to remove GUID: %u", GUID_LOPART(guid
));
319 GroupQueueInfo
* group
= itr
->second
.GroupInfo
;
320 GroupsQueueType::iterator group_itr
, group_itr_tmp
;
321 // mostly people with the highest levels are in battlegrounds, thats why
322 // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0
323 // variable index removes useless searching in other team's queue
324 uint32 index
= (group
->Team
== HORDE
) ? BG_TEAM_HORDE
: BG_TEAM_ALLIANCE
;
326 for (int32 bracket_id_tmp
= MAX_BATTLEGROUND_BRACKETS
- 1; bracket_id_tmp
>= 0 && bracket_id
== -1; --bracket_id_tmp
)
328 //we must check premade and normal team's queue - because when players from premade are joining bg,
329 //they leave groupinfo so we can't use its players size to find out index
330 for (uint32 j
= index
; j
< BG_QUEUE_GROUP_TYPES_COUNT
; j
+= BG_QUEUE_NORMAL_ALLIANCE
)
332 for(group_itr_tmp
= m_QueuedGroups
[bracket_id_tmp
][j
].begin(); group_itr_tmp
!= m_QueuedGroups
[bracket_id_tmp
][j
].end(); ++group_itr_tmp
)
334 if ((*group_itr_tmp
) == group
)
336 bracket_id
= bracket_id_tmp
;
337 group_itr
= group_itr_tmp
;
338 //we must store index to be able to erase iterator
345 //player can't be in queue without group, but just in case
346 if (bracket_id
== -1)
348 sLog
.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid
));
351 sLog
.outDebug("BattleGroundQueue: Removing player GUID %u, from bracket_id %u", GUID_LOPART(guid
), (uint32
)bracket_id
);
353 // ALL variables are correctly set
354 // We can ignore leveling up in queue - it should not cause crash
355 // remove player from group
356 // if only one player there, remove group
358 // remove player queue info from group queue info
359 std::map
<uint64
, PlayerQueueInfo
*>::iterator pitr
= group
->Players
.find(guid
);
360 if (pitr
!= group
->Players
.end())
361 group
->Players
.erase(pitr
);
363 // if invited to bg, and should decrease invited count, then do it
364 if (decreaseInvitedCount
&& group
->IsInvitedToBGInstanceGUID
)
366 BattleGround
* bg
= sBattleGroundMgr
.GetBattleGround(group
->IsInvitedToBGInstanceGUID
, group
->BgTypeId
);
368 bg
->DecreaseInvitedCount(group
->Team
);
371 // remove player queue info
372 m_QueuedPlayers
.erase(itr
);
374 // announce to world if arena team left queue for rated match, show only once
375 if (group
->ArenaType
&& group
->IsRated
&& group
->Players
.empty() && sWorld
.getConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_ENABLE
))
376 sWorld
.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT
, group
->ArenaType
, group
->ArenaType
, group
->ArenaTeamRating
);
378 //if player leaves queue and he is invited to rated arena match, then he have to loose
379 if (group
->IsInvitedToBGInstanceGUID
&& group
->IsRated
&& decreaseInvitedCount
)
381 ArenaTeam
* at
= sObjectMgr
.GetArenaTeamById(group
->ArenaTeamId
);
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
[bracket_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 BattleGroundBracketId bracket_id
= bg
->GetBracketId();
458 // set ArenaTeamId for rated matches
459 if (bg
->isArena() && bg
->isRated())
460 bg
->SetArenaTeamIdForTeam(ginfo
->Team
, ginfo
->ArenaTeamId
);
462 ginfo
->RemoveInviteTime
= getMSTime() + INVITE_ACCEPT_WAIT_TIME
;
464 // loop through the players
465 for(std::map
<uint64
,PlayerQueueInfo
*>::iterator itr
= ginfo
->Players
.begin(); itr
!= ginfo
->Players
.end(); ++itr
)
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
, bracket_id
);
475 //sBattleGroundMgr.InvitePlayer(plr, bg, ginfo->Team);
477 // set invited player counters
478 bg
->IncreaseInvitedCount(ginfo
->Team
);
480 plr
->SetInviteForBattleGroundQueueType(bgQueueTypeId
, ginfo
->IsInvitedToBGInstanceGUID
);
482 // create remind invite events
483 BGQueueInviteEvent
* inviteEvent
= new BGQueueInviteEvent(plr
->GetGUID(), ginfo
->IsInvitedToBGInstanceGUID
, bgTypeId
, ginfo
->ArenaType
, ginfo
->RemoveInviteTime
);
484 plr
->m_Events
.AddEvent(inviteEvent
, plr
->m_Events
.CalculateTime(INVITATION_REMIND_TIME
));
485 // create automatic remove events
486 BGQueueRemoveEvent
* removeEvent
= new BGQueueRemoveEvent(plr
->GetGUID(), ginfo
->IsInvitedToBGInstanceGUID
, bgTypeId
, bgQueueTypeId
, ginfo
->RemoveInviteTime
);
487 plr
->m_Events
.AddEvent(removeEvent
, plr
->m_Events
.CalculateTime(INVITE_ACCEPT_WAIT_TIME
));
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
, BattleGroundBracketId bracket_id
)
512 int32 hordeFree
= bg
->GetFreeSlotsForTeam(HORDE
);
513 int32 aliFree
= bg
->GetFreeSlotsForTeam(ALLIANCE
);
515 //iterator for iterating through bg queue
516 GroupsQueueType::const_iterator Ali_itr
= m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
].begin();
517 //count of groups in queue - used to stop cycles
518 uint32 aliCount
= m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
].size();
519 //index to queue which group is current
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
[bracket_id
][BG_QUEUE_NORMAL_HORDE
].begin();
525 uint32 hordeCount
= m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_HORDE
].size();
526 uint32 hordeIndex
= 0;
527 for (; hordeIndex
< hordeCount
&& m_SelectionPools
[BG_TEAM_HORDE
].AddGroup((*Horde_itr
), hordeFree
); hordeIndex
++)
530 //if ofc like BG queue invitation is set in config, then we are happy
531 if (sWorld
.getConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE
) == 0)
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(BattleGroundBracketId bracket_id
, uint32 MinPlayersPerTeam
, uint32 MaxPlayersPerTeam
)
591 if (!m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].empty() && !m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].empty())
593 //start premade match
594 //if groups aren't invited
595 GroupsQueueType::const_iterator ali_group
, horde_group
;
596 for( ali_group
= m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].begin(); ali_group
!= m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].end(); ++ali_group
)
597 if (!(*ali_group
)->IsInvitedToBGInstanceGUID
)
599 for( horde_group
= m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].begin(); horde_group
!= m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].end(); ++horde_group
)
600 if (!(*horde_group
)->IsInvitedToBGInstanceGUID
)
603 if (ali_group
!= m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].end() && horde_group
!= m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].end())
605 m_SelectionPools
[BG_TEAM_ALLIANCE
].AddGroup((*ali_group
), MaxPlayersPerTeam
);
606 m_SelectionPools
[BG_TEAM_HORDE
].AddGroup((*horde_group
), MaxPlayersPerTeam
);
607 //add groups/players from normal queue to size of bigger group
608 uint32 maxPlayers
= std::max(m_SelectionPools
[BG_TEAM_ALLIANCE
].GetPlayerCount(), m_SelectionPools
[BG_TEAM_HORDE
].GetPlayerCount());
609 GroupsQueueType::const_iterator itr
;
610 for(uint32 i
= 0; i
< BG_TEAMS_COUNT
; i
++)
612 for(itr
= m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
+ i
].begin(); itr
!= m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
+ i
].end(); ++itr
)
614 //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
615 if (!(*itr
)->IsInvitedToBGInstanceGUID
&& !m_SelectionPools
[i
].AddGroup((*itr
), maxPlayers
))
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_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH
);
628 for(uint32 i
= 0; i
< BG_TEAMS_COUNT
; i
++)
630 if (!m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
+ i
].empty())
632 GroupsQueueType::iterator itr
= m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
+ i
].begin();
633 if (!(*itr
)->IsInvitedToBGInstanceGUID
&& ((*itr
)->JoinTime
< time_before
|| (*itr
)->Players
.size() < MinPlayersPerTeam
))
635 //we must insert group to normal queue and erase pointer from premade queue
636 m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
+ i
].push_front((*itr
));
637 m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
+ i
].erase(itr
);
641 //selection pools are not set
645 // this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
646 bool BattleGroundQueue::CheckNormalMatch(BattleGround
* bg_template
, BattleGroundBracketId bracket_id
, uint32 minPlayers
, uint32 maxPlayers
)
648 GroupsQueueType::const_iterator itr_team
[BG_TEAMS_COUNT
];
649 for(uint32 i
= 0; i
< BG_TEAMS_COUNT
; i
++)
651 itr_team
[i
] = m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
+ i
].begin();
652 for(; itr_team
[i
] != m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
+ i
].end(); ++(itr_team
[i
]))
654 if (!(*(itr_team
[i
]))->IsInvitedToBGInstanceGUID
)
656 m_SelectionPools
[i
].AddGroup(*(itr_team
[i
]), maxPlayers
);
657 if (m_SelectionPools
[i
].GetPlayerCount() >= minPlayers
)
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_UINT32_BATTLEGROUND_INVITATION_TYPE
) != 0
667 && m_SelectionPools
[BG_TEAM_HORDE
].GetPlayerCount() >= minPlayers
&& m_SelectionPools
[BG_TEAM_ALLIANCE
].GetPlayerCount() >= minPlayers
)
669 //we will try to invite more groups to team with less players indexed by j
670 ++(itr_team
[j
]); //this will not cause a crash, because for cycle above reached break;
671 for(; itr_team
[j
] != m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
+ j
].end(); ++(itr_team
[j
]))
673 if (!(*(itr_team
[j
]))->IsInvitedToBGInstanceGUID
)
674 if (!m_SelectionPools
[j
].AddGroup(*(itr_team
[j
]), m_SelectionPools
[(j
+ 1) % BG_TEAMS_COUNT
].GetPlayerCount()))
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(BattleGroundBracketId bracket_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
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
+ teamIndex
].begin();
708 for(; itr_team
!= m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
+ teamIndex
].end(); ++itr_team
)
709 if (ginfo
== *itr_team
)
711 if (itr_team
== m_QueuedGroups
[bracket_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
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
+ teamIndex
].end(); ++itr_team2
)
718 //if selection pool is full then break;
719 if (!(*itr_team2
)->IsInvitedToBGInstanceGUID
&& !m_SelectionPools
[otherTeam
].AddGroup(*itr_team2
, minPlayersPerTeam
))
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
[bracket_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
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
+ teamIndex
].end(); ++itr2
)
739 m_QueuedGroups
[bracket_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
, BattleGroundBracketId bracket_id
, uint8 arenaType
, bool isRated
, uint32 arenaRating
)
754 //ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock);
755 //if no players in queue - do nothing
756 if( m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].empty() &&
757 m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].empty() &&
758 m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_ALLIANCE
].empty() &&
759 m_QueuedGroups
[bracket_id
][BG_QUEUE_NORMAL_HORDE
].empty() )
762 //battleground with free slot for player should be always in the beggining of the queue
763 // maybe it would be better to create bgfreeslotqueue for each bracket_id
764 BGFreeSlotQueueType::iterator itr
, next
;
765 for (itr
= sBattleGroundMgr
.BGFreeSlotQueue
[bgTypeId
].begin(); itr
!= sBattleGroundMgr
.BGFreeSlotQueue
[bgTypeId
].end(); itr
= next
)
769 // DO NOT allow queue manager to invite new player to arena
770 if( (*itr
)->isBattleGround() && (*itr
)->GetTypeID() == bgTypeId
&& (*itr
)->GetBracketId() == bracket_id
&&
771 (*itr
)->GetStatus() > STATUS_WAIT_QUEUE
&& (*itr
)->GetStatus() < STATUS_WAIT_LEAVE
)
773 BattleGround
* bg
= *itr
; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
774 // and iterator is invalid
776 // clear selection pools
777 m_SelectionPools
[BG_TEAM_ALLIANCE
].Init();
778 m_SelectionPools
[BG_TEAM_HORDE
].Init();
780 // call a function that does the job for us
781 FillPlayersToBG(bg
, bracket_id
);
783 // now everything is set, invite players
784 for(GroupsQueueType::const_iterator citr
= m_SelectionPools
[BG_TEAM_ALLIANCE
].SelectedGroups
.begin(); citr
!= m_SelectionPools
[BG_TEAM_ALLIANCE
].SelectedGroups
.end(); ++citr
)
785 InviteGroupToBG((*citr
), bg
, (*citr
)->Team
);
786 for(GroupsQueueType::const_iterator citr
= m_SelectionPools
[BG_TEAM_HORDE
].SelectedGroups
.begin(); citr
!= m_SelectionPools
[BG_TEAM_HORDE
].SelectedGroups
.end(); ++citr
)
787 InviteGroupToBG((*citr
), bg
, (*citr
)->Team
);
789 if (!bg
->HasFreeSlots())
791 // remove BG from BGFreeSlotQueue
792 bg
->RemoveFromBGFreeSlotQueue();
797 // finished iterating through the bgs with free slots, maybe we need to create a new bg
799 BattleGround
* bg_template
= sBattleGroundMgr
.GetBattleGroundTemplate(bgTypeId
);
802 sLog
.outError("Battleground: Update: bg template not found for %u", bgTypeId
);
806 PvPDifficultyEntry
const* bracketEntry
= GetBattlegroundBracketById(bg_template
->GetMapId(),bracket_id
);
809 sLog
.outError("Battleground: Update: bg bracket entry not found for map %u bracket id %u", bg_template
->GetMapId(), bracket_id
);
813 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
814 uint32 MinPlayersPerTeam
= bg_template
->GetMinPlayersPerTeam();
815 uint32 MaxPlayersPerTeam
= bg_template
->GetMaxPlayersPerTeam();
816 if (sBattleGroundMgr
.isTesting())
817 MinPlayersPerTeam
= 1;
818 if (bg_template
->isArena())
820 if (sBattleGroundMgr
.isArenaTesting())
822 MaxPlayersPerTeam
= 1;
823 MinPlayersPerTeam
= 1;
827 //this switch can be much shorter
828 MaxPlayersPerTeam
= arenaType
;
829 MinPlayersPerTeam
= arenaType
;
833 MaxPlayersPerTeam = 2;
834 MinPlayersPerTeam = 2;
837 MaxPlayersPerTeam = 3;
838 MinPlayersPerTeam = 3;
841 MaxPlayersPerTeam = 5;
842 MinPlayersPerTeam = 5;
848 m_SelectionPools
[BG_TEAM_ALLIANCE
].Init();
849 m_SelectionPools
[BG_TEAM_HORDE
].Init();
851 if (bg_template
->isBattleGround())
853 //check if there is premade against premade match
854 if (CheckPremadeMatch(bracket_id
, MinPlayersPerTeam
, MaxPlayersPerTeam
))
856 //create new battleground
857 BattleGround
* bg2
= sBattleGroundMgr
.CreateNewBattleGround(bgTypeId
, bracketEntry
, 0, false);
860 sLog
.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId
);
863 //invite those selection pools
864 for(uint32 i
= 0; i
< BG_TEAMS_COUNT
; i
++)
865 for(GroupsQueueType::const_iterator citr
= m_SelectionPools
[BG_TEAM_ALLIANCE
+ i
].SelectedGroups
.begin(); citr
!= m_SelectionPools
[BG_TEAM_ALLIANCE
+ i
].SelectedGroups
.end(); ++citr
)
866 InviteGroupToBG((*citr
), bg2
, (*citr
)->Team
);
868 bg2
->StartBattleGround();
870 m_SelectionPools
[BG_TEAM_ALLIANCE
].Init();
871 m_SelectionPools
[BG_TEAM_HORDE
].Init();
875 // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
878 // if there are enough players in pools, start new battleground or non rated arena
879 if (CheckNormalMatch(bg_template
, bracket_id
, MinPlayersPerTeam
, MaxPlayersPerTeam
)
880 || (bg_template
->isArena() && CheckSkirmishForSameFaction(bracket_id
, MinPlayersPerTeam
)) )
882 // we successfully created a pool
883 BattleGround
* bg2
= sBattleGroundMgr
.CreateNewBattleGround(bgTypeId
, bracketEntry
, arenaType
, false);
886 sLog
.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId
);
890 // invite those selection pools
891 for(uint32 i
= 0; i
< BG_TEAMS_COUNT
; i
++)
892 for(GroupsQueueType::const_iterator citr
= m_SelectionPools
[BG_TEAM_ALLIANCE
+ i
].SelectedGroups
.begin(); citr
!= m_SelectionPools
[BG_TEAM_ALLIANCE
+ i
].SelectedGroups
.end(); ++citr
)
893 InviteGroupToBG((*citr
), bg2
, (*citr
)->Team
);
895 bg2
->StartBattleGround();
898 else if (bg_template
->isArena())
900 // found out the minimum and maximum ratings the newly added team should battle against
901 // arenaRating is the rating of the latest joined team, or 0
902 // 0 is on (automatic update call) and we must set it to team's with longest wait time
905 GroupQueueInfo
* front1
= NULL
;
906 GroupQueueInfo
* front2
= NULL
;
907 if (!m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].empty())
909 front1
= m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].front();
910 arenaRating
= front1
->ArenaTeamRating
;
912 if (!m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].empty())
914 front2
= m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].front();
915 arenaRating
= front2
->ArenaTeamRating
;
917 if (front1
&& front2
)
919 if (front1
->JoinTime
< front2
->JoinTime
)
920 arenaRating
= front1
->ArenaTeamRating
;
922 else if (!front1
&& !front2
)
923 return; //queues are empty
927 uint32 arenaMinRating
= (arenaRating
<= sBattleGroundMgr
.GetMaxRatingDifference()) ? 0 : arenaRating
- sBattleGroundMgr
.GetMaxRatingDifference();
928 uint32 arenaMaxRating
= arenaRating
+ sBattleGroundMgr
.GetMaxRatingDifference();
929 // if max rating difference is set and the time past since server startup is greater than the rating discard time
930 // (after what time the ratings aren't taken into account when making teams) then
931 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
932 // else leave the discard time on 0, this way all ratings will be discarded
933 uint32 discardTime
= getMSTime() - sBattleGroundMgr
.GetRatingDiscardTimer();
935 // we need to find 2 teams which will play next game
937 GroupsQueueType::iterator itr_team
[BG_TEAMS_COUNT
];
939 //optimalization : --- we dont need to use selection_pools - each update we select max 2 groups
941 for(uint32 i
= BG_QUEUE_PREMADE_ALLIANCE
; i
< BG_QUEUE_NORMAL_ALLIANCE
; i
++)
943 // take the group that joined first
944 itr_team
[i
] = m_QueuedGroups
[bracket_id
][i
].begin();
945 for(; itr_team
[i
] != m_QueuedGroups
[bracket_id
][i
].end(); ++(itr_team
[i
]))
947 // if group match conditions, then add it to pool
948 if( !(*itr_team
[i
])->IsInvitedToBGInstanceGUID
949 && (((*itr_team
[i
])->ArenaTeamRating
>= arenaMinRating
&& (*itr_team
[i
])->ArenaTeamRating
<= arenaMaxRating
)
950 || (*itr_team
[i
])->JoinTime
< discardTime
) )
952 m_SelectionPools
[i
].AddGroup((*itr_team
[i
]), MaxPlayersPerTeam
);
953 // break for cycle to be able to start selecting another group from same faction queue
958 // now we are done if we have 2 groups - ali vs horde!
959 // if we don't have, we must try to continue search in same queue
960 // tmp variables are correctly set
961 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue
962 if (m_SelectionPools
[BG_TEAM_ALLIANCE
].GetPlayerCount() == 0 && m_SelectionPools
[BG_TEAM_HORDE
].GetPlayerCount())
964 itr_team
[BG_TEAM_ALLIANCE
] = itr_team
[BG_TEAM_HORDE
];
965 ++itr_team
[BG_TEAM_ALLIANCE
];
966 for(; itr_team
[BG_TEAM_ALLIANCE
] != m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].end(); ++(itr_team
[BG_TEAM_ALLIANCE
]))
968 if( !(*itr_team
[BG_TEAM_ALLIANCE
])->IsInvitedToBGInstanceGUID
969 && (((*itr_team
[BG_TEAM_ALLIANCE
])->ArenaTeamRating
>= arenaMinRating
&& (*itr_team
[BG_TEAM_ALLIANCE
])->ArenaTeamRating
<= arenaMaxRating
)
970 || (*itr_team
[BG_TEAM_ALLIANCE
])->JoinTime
< discardTime
) )
972 m_SelectionPools
[BG_TEAM_ALLIANCE
].AddGroup((*itr_team
[BG_TEAM_ALLIANCE
]), MaxPlayersPerTeam
);
977 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue
978 if (m_SelectionPools
[BG_TEAM_HORDE
].GetPlayerCount() == 0 && m_SelectionPools
[BG_TEAM_ALLIANCE
].GetPlayerCount())
980 itr_team
[BG_TEAM_HORDE
] = itr_team
[BG_TEAM_ALLIANCE
];
981 ++itr_team
[BG_TEAM_HORDE
];
982 for(; itr_team
[BG_TEAM_HORDE
] != m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].end(); ++(itr_team
[BG_TEAM_HORDE
]))
984 if( !(*itr_team
[BG_TEAM_HORDE
])->IsInvitedToBGInstanceGUID
985 && (((*itr_team
[BG_TEAM_HORDE
])->ArenaTeamRating
>= arenaMinRating
&& (*itr_team
[BG_TEAM_HORDE
])->ArenaTeamRating
<= arenaMaxRating
)
986 || (*itr_team
[BG_TEAM_HORDE
])->JoinTime
< discardTime
) )
988 m_SelectionPools
[BG_TEAM_HORDE
].AddGroup((*itr_team
[BG_TEAM_HORDE
]), MaxPlayersPerTeam
);
994 //if we have 2 teams, then start new arena and invite players!
995 if (m_SelectionPools
[BG_TEAM_ALLIANCE
].GetPlayerCount() && m_SelectionPools
[BG_TEAM_HORDE
].GetPlayerCount())
997 BattleGround
* arena
= sBattleGroundMgr
.CreateNewBattleGround(bgTypeId
, bracketEntry
, arenaType
, true);
1000 sLog
.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
1004 (*(itr_team
[BG_TEAM_ALLIANCE
]))->OpponentsTeamRating
= (*(itr_team
[BG_TEAM_HORDE
]))->ArenaTeamRating
;
1005 sLog
.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team
[BG_TEAM_ALLIANCE
]))->ArenaTeamId
, (*(itr_team
[BG_TEAM_ALLIANCE
]))->OpponentsTeamRating
);
1006 (*(itr_team
[BG_TEAM_HORDE
]))->OpponentsTeamRating
= (*(itr_team
[BG_TEAM_ALLIANCE
]))->ArenaTeamRating
;
1007 sLog
.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team
[BG_TEAM_HORDE
]))->ArenaTeamId
, (*(itr_team
[BG_TEAM_HORDE
]))->OpponentsTeamRating
);
1008 // now we must move team if we changed its faction to another faction queue, because then we will spam log by errors in Queue::RemovePlayer
1009 if ((*(itr_team
[BG_TEAM_ALLIANCE
]))->Team
!= ALLIANCE
)
1011 // add to alliance queue
1012 m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].push_front(*(itr_team
[BG_TEAM_ALLIANCE
]));
1013 // erase from horde queue
1014 m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].erase(itr_team
[BG_TEAM_ALLIANCE
]);
1015 itr_team
[BG_TEAM_ALLIANCE
] = m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].begin();
1017 if ((*(itr_team
[BG_TEAM_HORDE
]))->Team
!= HORDE
)
1019 m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].push_front(*(itr_team
[BG_TEAM_HORDE
]));
1020 m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_ALLIANCE
].erase(itr_team
[BG_TEAM_HORDE
]);
1021 itr_team
[BG_TEAM_HORDE
] = m_QueuedGroups
[bracket_id
][BG_QUEUE_PREMADE_HORDE
].begin();
1024 InviteGroupToBG(*(itr_team
[BG_TEAM_ALLIANCE
]), arena
, ALLIANCE
);
1025 InviteGroupToBG(*(itr_team
[BG_TEAM_HORDE
]), arena
, HORDE
);
1027 sLog
.outDebug("Starting rated arena match!");
1029 arena
->StartBattleGround();
1034 /*********************************************************/
1035 /*** BATTLEGROUND QUEUE EVENTS ***/
1036 /*********************************************************/
1038 bool BGQueueInviteEvent::Execute(uint64
/*e_time*/, uint32
/*p_time*/)
1040 Player
* plr
= sObjectMgr
.GetPlayer( m_PlayerGuid
);
1041 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1045 BattleGround
* bg
= sBattleGroundMgr
.GetBattleGround(m_BgInstanceGUID
, m_BgTypeId
);
1046 //if battleground ended and its instance deleted - do nothing
1050 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(bg
->GetTypeID(), bg
->GetArenaType());
1051 uint32 queueSlot
= plr
->GetBattleGroundQueueIndex(bgQueueTypeId
);
1052 if (queueSlot
< PLAYER_MAX_BATTLEGROUND_QUEUES
) // player is in queue or in battleground
1054 // check if player is invited to this bg
1055 BattleGroundQueue
&bgQueue
= sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
];
1056 if (bgQueue
.IsPlayerInvited(m_PlayerGuid
, m_BgInstanceGUID
, m_RemoveTime
))
1059 //we must send remaining time in queue
1060 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, queueSlot
, STATUS_WAIT_JOIN
, INVITE_ACCEPT_WAIT_TIME
- INVITATION_REMIND_TIME
, 0, m_ArenaType
);
1061 plr
->GetSession()->SendPacket(&data
);
1064 return true; //event will be deleted
1067 void BGQueueInviteEvent::Abort(uint64
/*e_time*/)
1073 this event has many possibilities when it is executed:
1074 1. player is in battleground ( he clicked enter on invitation window )
1075 2. player left battleground queue and he isn't there any more
1076 3. player left battleground queue and he joined it again and IsInvitedToBGInstanceGUID = 0
1077 4. player left queue and he joined again and he has been invited to same battleground again -> we should not remove him from queue yet
1078 5. player is invited to bg and he didn't choose what to do and timer expired - only in this condition we should call queue::RemovePlayer
1079 we must remove player in the 5. case even if battleground object doesn't exist!
1081 bool BGQueueRemoveEvent::Execute(uint64
/*e_time*/, uint32
/*p_time*/)
1083 Player
* plr
= sObjectMgr
.GetPlayer( m_PlayerGuid
);
1085 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1088 BattleGround
* bg
= sBattleGroundMgr
.GetBattleGround(m_BgInstanceGUID
, m_BgTypeId
);
1089 //battleground can be deleted already when we are removing queue info
1090 //bg pointer can be NULL! so use it carefully!
1092 uint32 queueSlot
= plr
->GetBattleGroundQueueIndex(m_BgQueueTypeId
);
1093 if (queueSlot
< PLAYER_MAX_BATTLEGROUND_QUEUES
) // player is in queue, or in Battleground
1095 // check if player is in queue for this BG and if we are removing his invite event
1096 BattleGroundQueue
&bgQueue
= sBattleGroundMgr
.m_BattleGroundQueues
[m_BgQueueTypeId
];
1097 if (bgQueue
.IsPlayerInvited(m_PlayerGuid
, m_BgInstanceGUID
, m_RemoveTime
))
1099 sLog
.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr
->GetGUIDLow(),m_BgInstanceGUID
);
1101 plr
->RemoveBattleGroundQueueId(m_BgQueueTypeId
);
1102 bgQueue
.RemovePlayer(m_PlayerGuid
, true);
1103 //update queues if battleground isn't ended
1104 if (bg
&& bg
->isBattleGround() && bg
->GetStatus() != STATUS_WAIT_LEAVE
)
1105 sBattleGroundMgr
.ScheduleQueueUpdate(0, 0, m_BgQueueTypeId
, m_BgTypeId
, bg
->GetBracketId());
1108 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, bg
, queueSlot
, STATUS_NONE
, 0, 0, 0);
1109 plr
->GetSession()->SendPacket(&data
);
1113 //event will be deleted
1117 void BGQueueRemoveEvent::Abort(uint64
/*e_time*/)
1122 /*********************************************************/
1123 /*** BATTLEGROUND MANAGER ***/
1124 /*********************************************************/
1126 BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
1128 for(uint32 i
= BATTLEGROUND_TYPE_NONE
; i
< MAX_BATTLEGROUND_TYPE_ID
; i
++)
1129 m_BattleGrounds
[i
].clear();
1130 m_NextRatingDiscardUpdate
= sWorld
.getConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER
);
1134 BattleGroundMgr::~BattleGroundMgr()
1136 DeleteAllBattleGrounds();
1139 void BattleGroundMgr::DeleteAllBattleGrounds()
1141 for(uint32 i
= BATTLEGROUND_TYPE_NONE
; i
< MAX_BATTLEGROUND_TYPE_ID
; i
++)
1143 for(BattleGroundSet::iterator itr
= m_BattleGrounds
[i
].begin(); itr
!= m_BattleGrounds
[i
].end();)
1145 BattleGround
* bg
= itr
->second
;
1146 m_BattleGrounds
[i
].erase(itr
++);
1147 if (!m_ClientBattleGroundIds
[i
][bg
->GetBracketId()].empty())
1148 m_ClientBattleGroundIds
[i
][bg
->GetBracketId()].erase(bg
->GetClientInstanceID());
1153 // destroy template battlegrounds that listed only in queues (other already terminated)
1154 for(uint32 bgTypeId
= 0; bgTypeId
< MAX_BATTLEGROUND_TYPE_ID
; ++bgTypeId
)
1156 // ~BattleGround call unregistring BG from queue
1157 while(!BGFreeSlotQueue
[bgTypeId
].empty())
1158 delete BGFreeSlotQueue
[bgTypeId
].front();
1162 // used to update running battlegrounds, and delete finished ones
1163 void BattleGroundMgr::Update(uint32 diff
)
1165 BattleGroundSet::iterator itr
, next
;
1166 for(uint32 i
= BATTLEGROUND_TYPE_NONE
; i
< MAX_BATTLEGROUND_TYPE_ID
; i
++)
1168 itr
= m_BattleGrounds
[i
].begin();
1169 // skip updating battleground template
1170 if (itr
!= m_BattleGrounds
[i
].end())
1172 for(; itr
!= m_BattleGrounds
[i
].end(); itr
= next
)
1176 itr
->second
->Update(diff
);
1177 // use the SetDeleteThis variable
1178 // direct deletion caused crashes
1179 if (itr
->second
->m_SetDeleteThis
)
1181 BattleGround
* bg
= itr
->second
;
1182 m_BattleGrounds
[i
].erase(itr
);
1183 if (!m_ClientBattleGroundIds
[i
][bg
->GetBracketId()].empty())
1184 m_ClientBattleGroundIds
[i
][bg
->GetBracketId()].erase(bg
->GetClientInstanceID());
1190 // update scheduled queues
1191 if (!m_QueueUpdateScheduler
.empty())
1193 std::vector
<uint64
> scheduled
;
1196 //ACE_Guard<ACE_Thread_Mutex> guard(SchedulerLock);
1197 //copy vector and clear the other
1198 scheduled
= std::vector
<uint64
>(m_QueueUpdateScheduler
);
1199 m_QueueUpdateScheduler
.clear();
1203 for (uint8 i
= 0; i
< scheduled
.size(); i
++)
1205 uint32 arenaRating
= scheduled
[i
] >> 32;
1206 uint8 arenaType
= scheduled
[i
] >> 24 & 255;
1207 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundQueueTypeId(scheduled
[i
] >> 16 & 255);
1208 BattleGroundTypeId bgTypeId
= BattleGroundTypeId((scheduled
[i
] >> 8) & 255);
1209 BattleGroundBracketId bracket_id
= BattleGroundBracketId(scheduled
[i
] & 255);
1210 m_BattleGroundQueues
[bgQueueTypeId
].Update(bgTypeId
, bracket_id
, arenaType
, arenaRating
> 0, arenaRating
);
1214 // if rating difference counts, maybe force-update queues
1215 if (sWorld
.getConfig(CONFIG_UINT32_ARENA_MAX_RATING_DIFFERENCE
) && sWorld
.getConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER
))
1217 // it's time to force update
1218 if (m_NextRatingDiscardUpdate
< diff
)
1220 // forced update for rated arenas (scan all, but skipped non rated)
1221 sLog
.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
1222 for(int qtype
= BATTLEGROUND_QUEUE_2v2
; qtype
<= BATTLEGROUND_QUEUE_5v5
; ++qtype
)
1223 for(int bracket
= BG_BRACKET_ID_FIRST
; bracket
< MAX_BATTLEGROUND_BRACKETS
; ++bracket
)
1224 m_BattleGroundQueues
[qtype
].Update(
1225 BATTLEGROUND_AA
, BattleGroundBracketId(bracket
),
1226 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId(qtype
)), true, 0);
1228 m_NextRatingDiscardUpdate
= sWorld
.getConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER
);
1231 m_NextRatingDiscardUpdate
-= diff
;
1233 if (sWorld
.getConfig(CONFIG_BOOL_ARENA_AUTO_DISTRIBUTE_POINTS
))
1235 if (m_AutoDistributionTimeChecker
< diff
)
1237 if (sWorld
.GetGameTime() > m_NextAutoDistributionTime
)
1239 DistributeArenaPoints();
1240 m_NextAutoDistributionTime
= time_t(sWorld
.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY
* sWorld
.getConfig(CONFIG_UINT32_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS
));
1241 CharacterDatabase
.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"UI64FMTD
"'", uint64(m_NextAutoDistributionTime
));
1243 m_AutoDistributionTimeChecker
= 600000; // check 10 minutes
1246 m_AutoDistributionTimeChecker
-= diff
;
1250 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket
*data
, BattleGround
*bg
, uint8 QueueSlot
, uint8 StatusID
, uint32 Time1
, uint32 Time2
, uint8 arenatype
)
1252 // we can be in 2 queues in same time...
1254 if (StatusID
== 0 || !bg
)
1256 data
->Initialize(SMSG_BATTLEFIELD_STATUS
, 4+8);
1257 *data
<< uint32(QueueSlot
); // queue id (0...1)
1262 data
->Initialize(SMSG_BATTLEFIELD_STATUS
, (4+8+1+1+4+1+4+4+4));
1263 *data
<< uint32(QueueSlot
); // queue id (0...1) - player can be in 2 queues in time
1265 *data
<< uint64( uint64(arenatype
) | (uint64(0x0D) << 8) | (uint64(bg
->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1266 *data
<< uint8(0); // 3.3.0
1267 *data
<< uint8(0); // 3.3.0
1268 *data
<< uint32(bg
->GetClientInstanceID());
1269 // alliance/horde for BG and skirmish/rated for Arenas
1270 // following displays the minimap-icon 0 = faction icon 1 = arenaicon
1271 *data
<< uint8(bg
->isRated());
1272 *data
<< uint32(StatusID
); // status
1275 case STATUS_WAIT_QUEUE
: // status_in_queue
1276 *data
<< uint32(Time1
); // average wait time, milliseconds
1277 *data
<< uint32(Time2
); // time in queue, updated every minute!, milliseconds
1279 case STATUS_WAIT_JOIN
: // status_invite
1280 *data
<< uint32(bg
->GetMapId()); // map id
1281 *data
<< uint32(Time1
); // time to remove from queue, milliseconds
1283 case STATUS_IN_PROGRESS
: // status_in_progress
1284 *data
<< uint32(bg
->GetMapId()); // map id
1285 *data
<< uint32(Time1
); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
1286 *data
<< uint32(Time2
); // time from bg start, milliseconds
1287 *data
<< uint8(0x1); // unk sometimes 0x0!
1290 sLog
.outError("Unknown BG status!");
1295 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket
*data
, BattleGround
*bg
)
1297 uint8 type
= (bg
->isArena() ? 1 : 0);
1298 // last check on 3.0.3
1299 data
->Initialize(MSG_PVP_LOG_DATA
, (1+1+4+40*bg
->GetPlayerScoresSize()));
1300 *data
<< uint8(type
); // type (battleground=0/arena=1)
1304 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1305 for(int i
= 1; i
>= 0; --i
)
1307 *data
<< uint32(bg
->m_ArenaTeamRatingChanges
[i
]);
1308 *data
<< uint32(3999); // huge thanks for TOM_RUS for this!
1309 *data
<< uint32(0); // added again in 3.1
1310 sLog
.outDebug("rating change: %d", bg
->m_ArenaTeamRatingChanges
[i
]);
1312 for(int i
= 1; i
>= 0; --i
)
1314 uint32 at_id
= bg
->m_ArenaTeamIds
[i
];
1315 ArenaTeam
* at
= sObjectMgr
.GetArenaTeamById(at_id
);
1317 *data
<< at
->GetName();
1323 if (bg
->GetStatus() != STATUS_WAIT_LEAVE
)
1325 *data
<< uint8(0); // bg not ended
1329 *data
<< uint8(1); // bg ended
1330 *data
<< uint8(bg
->GetWinner()); // who win
1333 *data
<< (int32
)(bg
->GetPlayerScoresSize());
1335 for(BattleGround::BattleGroundScoreMap::const_iterator itr
= bg
->GetPlayerScoresBegin(); itr
!= bg
->GetPlayerScoresEnd(); ++itr
)
1337 *data
<< (uint64
)itr
->first
;
1338 *data
<< (int32
)itr
->second
->KillingBlows
;
1341 *data
<< (int32
)itr
->second
->HonorableKills
;
1342 *data
<< (int32
)itr
->second
->Deaths
;
1343 *data
<< (int32
)(itr
->second
->BonusHonor
);
1347 Player
*plr
= sObjectMgr
.GetPlayer(itr
->first
);
1348 uint32 team
= bg
->GetPlayerTeam(itr
->first
);
1350 team
= plr
->GetTeam();
1351 if (( bg
->GetWinner()==0 && team
== ALLIANCE
) || ( bg
->GetWinner()==1 && team
==HORDE
))
1356 *data
<< (int32
)itr
->second
->DamageDone
; // damage done
1357 *data
<< (int32
)itr
->second
->HealingDone
; // healing done
1358 switch(bg
->GetTypeID()) // battleground specific things
1360 case BATTLEGROUND_AV
:
1361 *data
<< (uint32
)0x00000005; // count of next fields
1362 *data
<< (uint32
)((BattleGroundAVScore
*)itr
->second
)->GraveyardsAssaulted
; // GraveyardsAssaulted
1363 *data
<< (uint32
)((BattleGroundAVScore
*)itr
->second
)->GraveyardsDefended
; // GraveyardsDefended
1364 *data
<< (uint32
)((BattleGroundAVScore
*)itr
->second
)->TowersAssaulted
; // TowersAssaulted
1365 *data
<< (uint32
)((BattleGroundAVScore
*)itr
->second
)->TowersDefended
; // TowersDefended
1366 *data
<< (uint32
)((BattleGroundAVScore
*)itr
->second
)->SecondaryObjectives
; // SecondaryObjectives - free some of the Lieutnants
1368 case BATTLEGROUND_WS
:
1369 *data
<< (uint32
)0x00000002; // count of next fields
1370 *data
<< (uint32
)((BattleGroundWGScore
*)itr
->second
)->FlagCaptures
; // flag captures
1371 *data
<< (uint32
)((BattleGroundWGScore
*)itr
->second
)->FlagReturns
; // flag returns
1373 case BATTLEGROUND_AB
:
1374 *data
<< (uint32
)0x00000002; // count of next fields
1375 *data
<< (uint32
)((BattleGroundABScore
*)itr
->second
)->BasesAssaulted
; // bases asssulted
1376 *data
<< (uint32
)((BattleGroundABScore
*)itr
->second
)->BasesDefended
; // bases defended
1378 case BATTLEGROUND_EY
:
1379 *data
<< (uint32
)0x00000001; // count of next fields
1380 *data
<< (uint32
)((BattleGroundEYScore
*)itr
->second
)->FlagCaptures
; // flag captures
1382 case BATTLEGROUND_NA
:
1383 case BATTLEGROUND_BE
:
1384 case BATTLEGROUND_AA
:
1385 case BATTLEGROUND_RL
:
1386 case BATTLEGROUND_SA
: // wotlk
1387 case BATTLEGROUND_DS
: // wotlk
1388 case BATTLEGROUND_RV
: // wotlk
1389 case BATTLEGROUND_IC
: // wotlk
1390 case BATTLEGROUND_ABG
: // wotlk
1391 *data
<< (int32
)0; // 0
1394 sLog
.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg
->GetTypeID());
1401 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket
*data
, BattleGroundTypeId bgTypeId
)
1404 0 - Your group has joined a battleground queue, but you are not eligible
1405 1 - Your group has joined the queue for AV
1406 2 - Your group has joined the queue for WS
1407 3 - Your group has joined the queue for AB
1408 4 - Your group has joined the queue for NA
1409 5 - Your group has joined the queue for BE Arena
1410 6 - Your group has joined the queue for All Arenas
1411 7 - Your group has joined the queue for EotS*/
1412 data
->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND
, 4);
1413 *data
<< uint32(bgTypeId
);
1416 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket
*data
, uint32 field
, uint32 value
)
1418 data
->Initialize(SMSG_UPDATE_WORLD_STATE
, 4+4);
1419 *data
<< uint32(field
);
1420 *data
<< uint32(value
);
1423 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket
*data
, uint32 soundid
)
1425 data
->Initialize(SMSG_PLAY_SOUND
, 4);
1426 *data
<< uint32(soundid
);
1429 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket
*data
, const uint64
& guid
)
1431 data
->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT
, 8);
1432 *data
<< uint64(guid
);
1435 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket
*data
, Player
*plr
)
1437 data
->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED
, 8);
1438 *data
<< uint64(plr
->GetGUID());
1441 BattleGround
* BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId
, BattleGroundTypeId bgTypeId
)
1443 //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from
1444 //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
1445 BattleGround
* bg
= GetBattleGroundTemplate(bgTypeId
);
1450 return GetBattleGround(instanceId
, bgTypeId
);
1452 for(BattleGroundSet::iterator itr
= m_BattleGrounds
[bgTypeId
].begin(); itr
!= m_BattleGrounds
[bgTypeId
].end(); ++itr
)
1454 if (itr
->second
->GetClientInstanceID() == instanceId
)
1460 BattleGround
* BattleGroundMgr::GetBattleGround(uint32 InstanceID
, BattleGroundTypeId bgTypeId
)
1463 BattleGroundSet::iterator itr
;
1464 if (bgTypeId
== BATTLEGROUND_TYPE_NONE
)
1466 for(uint32 i
= BATTLEGROUND_AV
; i
< MAX_BATTLEGROUND_TYPE_ID
; i
++)
1468 itr
= m_BattleGrounds
[i
].find(InstanceID
);
1469 if (itr
!= m_BattleGrounds
[i
].end())
1474 itr
= m_BattleGrounds
[bgTypeId
].find(InstanceID
);
1475 return ( (itr
!= m_BattleGrounds
[bgTypeId
].end()) ? itr
->second
: NULL
);
1478 BattleGround
* BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId
)
1480 //map is sorted and we can be sure that lowest instance id has only BG template
1481 return m_BattleGrounds
[bgTypeId
].empty() ? NULL
: m_BattleGrounds
[bgTypeId
].begin()->second
;
1484 uint32
BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId
, BattleGroundBracketId bracket_id
)
1486 if (IsArenaType(bgTypeId
))
1487 return 0; //arenas don't have client-instanceids
1489 // we create here an instanceid, which is just for
1490 // displaying this to the client and without any other use..
1491 // the client-instanceIds are unique for each battleground-type
1492 // the instance-id just needs to be as low as possible, beginning with 1
1493 // the following works, because std::set is default ordered with "<"
1494 // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
1496 for(std::set
<uint32
>::iterator itr
= m_ClientBattleGroundIds
[bgTypeId
][bracket_id
].begin(); itr
!= m_ClientBattleGroundIds
[bgTypeId
][bracket_id
].end();)
1498 if( (++lastId
) != *itr
) //if there is a gap between the ids, we will break..
1502 m_ClientBattleGroundIds
[bgTypeId
][bracket_id
].insert(lastId
+ 1);
1506 // create a new battleground that will really be used to play
1507 BattleGround
* BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId
, PvPDifficultyEntry
const* bracketEntry
, uint8 arenaType
, bool isRated
)
1509 // get the template BG
1510 BattleGround
*bg_template
= GetBattleGroundTemplate(bgTypeId
);
1513 sLog
.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId
);
1517 //for arenas there is random map used
1518 if (bg_template
->isArena())
1520 BattleGroundTypeId arenas
[] = {BATTLEGROUND_NA
, BATTLEGROUND_BE
, BATTLEGROUND_RL
};
1521 uint32 arena_num
= urand(0,2);
1522 bgTypeId
= arenas
[arena_num
];
1523 bg_template
= GetBattleGroundTemplate(bgTypeId
);
1526 sLog
.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId
);
1531 BattleGround
*bg
= NULL
;
1532 // create a copy of the BG template
1535 case BATTLEGROUND_AV
:
1536 bg
= new BattleGroundAV(*(BattleGroundAV
*)bg_template
);
1538 case BATTLEGROUND_WS
:
1539 bg
= new BattleGroundWS(*(BattleGroundWS
*)bg_template
);
1541 case BATTLEGROUND_AB
:
1542 bg
= new BattleGroundAB(*(BattleGroundAB
*)bg_template
);
1544 case BATTLEGROUND_NA
:
1545 bg
= new BattleGroundNA(*(BattleGroundNA
*)bg_template
);
1547 case BATTLEGROUND_BE
:
1548 bg
= new BattleGroundBE(*(BattleGroundBE
*)bg_template
);
1550 case BATTLEGROUND_AA
:
1551 bg
= new BattleGroundAA(*(BattleGroundAA
*)bg_template
);
1553 case BATTLEGROUND_EY
:
1554 bg
= new BattleGroundEY(*(BattleGroundEY
*)bg_template
);
1556 case BATTLEGROUND_RL
:
1557 bg
= new BattleGroundRL(*(BattleGroundRL
*)bg_template
);
1559 case BATTLEGROUND_SA
:
1560 bg
= new BattleGroundSA(*(BattleGroundSA
*)bg_template
);
1562 case BATTLEGROUND_DS
:
1563 bg
= new BattleGroundDS(*(BattleGroundDS
*)bg_template
);
1565 case BATTLEGROUND_RV
:
1566 bg
= new BattleGroundRV(*(BattleGroundRV
*)bg_template
);
1568 case BATTLEGROUND_IC
:
1569 bg
= new BattleGroundIC(*(BattleGroundIC
*)bg_template
);
1571 case BATTLEGROUND_ABG
:
1572 bg
= new BattleGroundABG(*(BattleGroundABG
*)bg_template
);
1575 //error, but it is handled few lines above
1579 // generate a new instance id
1580 bg
->SetInstanceID(sMapMgr
.GenerateInstanceId()); // set instance id
1581 bg
->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId
, bracketEntry
->GetBracketId()));
1583 // reset the new bg (set status to status_wait_queue from status_none)
1586 // start the joining of the bg
1587 bg
->SetStatus(STATUS_WAIT_JOIN
);
1588 bg
->SetBracket(bracketEntry
);
1589 bg
->SetArenaType(arenaType
);
1590 bg
->SetRated(isRated
);
1595 // used to create the BG templates
1596 uint32
BattleGroundMgr::CreateBattleGround(BattleGroundTypeId bgTypeId
, bool IsArena
, uint32 MinPlayersPerTeam
, uint32 MaxPlayersPerTeam
, uint32 LevelMin
, uint32 LevelMax
, char* BattleGroundName
, uint32 MapID
, float Team1StartLocX
, float Team1StartLocY
, float Team1StartLocZ
, float Team1StartLocO
, float Team2StartLocX
, float Team2StartLocY
, float Team2StartLocZ
, float Team2StartLocO
)
1599 BattleGround
*bg
= NULL
;
1602 case BATTLEGROUND_AV
: bg
= new BattleGroundAV
; break;
1603 case BATTLEGROUND_WS
: bg
= new BattleGroundWS
; break;
1604 case BATTLEGROUND_AB
: bg
= new BattleGroundAB
; break;
1605 case BATTLEGROUND_NA
: bg
= new BattleGroundNA
; break;
1606 case BATTLEGROUND_BE
: bg
= new BattleGroundBE
; break;
1607 case BATTLEGROUND_AA
: bg
= new BattleGroundAA
; break;
1608 case BATTLEGROUND_EY
: bg
= new BattleGroundEY
; break;
1609 case BATTLEGROUND_RL
: bg
= new BattleGroundRL
; break;
1610 case BATTLEGROUND_SA
: bg
= new BattleGroundSA
; break;
1611 case BATTLEGROUND_DS
: bg
= new BattleGroundDS
; break;
1612 case BATTLEGROUND_RV
: bg
= new BattleGroundRV
; break;
1613 case BATTLEGROUND_IC
: bg
= new BattleGroundIC
; break;
1614 case BATTLEGROUND_ABG
: bg
= new BattleGroundABG
; break;
1615 default:bg
= new BattleGround
; break; // placeholder for non implemented BG
1618 bg
->SetMapId(MapID
);
1619 bg
->SetTypeID(bgTypeId
);
1620 bg
->SetInstanceID(0);
1621 bg
->SetArenaorBGType(IsArena
);
1622 bg
->SetMinPlayersPerTeam(MinPlayersPerTeam
);
1623 bg
->SetMaxPlayersPerTeam(MaxPlayersPerTeam
);
1624 bg
->SetMinPlayers(MinPlayersPerTeam
* 2);
1625 bg
->SetMaxPlayers(MaxPlayersPerTeam
* 2);
1626 bg
->SetName(BattleGroundName
);
1627 bg
->SetTeamStartLoc(ALLIANCE
, Team1StartLocX
, Team1StartLocY
, Team1StartLocZ
, Team1StartLocO
);
1628 bg
->SetTeamStartLoc(HORDE
, Team2StartLocX
, Team2StartLocY
, Team2StartLocZ
, Team2StartLocO
);
1629 bg
->SetLevelRange(LevelMin
, LevelMax
);
1631 // add bg to update list
1632 AddBattleGround(bg
->GetInstanceID(), bg
->GetTypeID(), bg
);
1634 // return some not-null value, bgTypeId is good enough for me
1638 void BattleGroundMgr::CreateInitialBattleGrounds()
1642 uint32 MaxPlayersPerTeam
, MinPlayersPerTeam
, MinLvl
, MaxLvl
, start1
, start2
;
1643 BattlemasterListEntry
const *bl
;
1644 WorldSafeLocsEntry
const *start
;
1649 // 0 1 2 3 4 5 6 7 8
1650 QueryResult
*result
= WorldDatabase
.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1659 sLog
.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1663 barGoLink
bar((int)result
->GetRowCount());
1667 Field
*fields
= result
->Fetch();
1670 uint32 bgTypeID_
= fields
[0].GetUInt32();
1672 // can be overwrite by values from DB
1673 bl
= sBattlemasterListStore
.LookupEntry(bgTypeID_
);
1676 sLog
.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_
);
1680 BattleGroundTypeId bgTypeID
= BattleGroundTypeId(bgTypeID_
);
1682 IsArena
= (bl
->type
== TYPE_ARENA
);
1683 MinPlayersPerTeam
= fields
[1].GetUInt32();
1684 MaxPlayersPerTeam
= fields
[2].GetUInt32();
1685 MinLvl
= fields
[3].GetUInt32();
1686 MaxLvl
= fields
[4].GetUInt32();
1687 //check values from DB
1688 if (MaxPlayersPerTeam
== 0 || MinPlayersPerTeam
== 0 || MinPlayersPerTeam
> MaxPlayersPerTeam
)
1690 MaxPlayersPerTeam
= bl
->maxplayersperteam
;
1691 MinPlayersPerTeam
= bl
->maxplayersperteam
; // by default now expected strong full bg requirement
1693 if (MinLvl
== 0 || MaxLvl
== 0 || MinLvl
> MaxLvl
)
1696 MinLvl
= 0;//bl->minlvl;
1697 MaxLvl
= 80;//bl->maxlvl;
1700 start1
= fields
[5].GetUInt32();
1702 start
= sWorldSafeLocsStore
.LookupEntry(start1
);
1705 AStartLoc
[0] = start
->x
;
1706 AStartLoc
[1] = start
->y
;
1707 AStartLoc
[2] = start
->z
;
1708 AStartLoc
[3] = fields
[6].GetFloat();
1710 else if (bgTypeID
== BATTLEGROUND_AA
|| bgTypeID
== BATTLEGROUND_ABG
)
1715 AStartLoc
[3] = fields
[6].GetFloat();
1719 sLog
.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID
, start1
);
1723 start2
= fields
[7].GetUInt32();
1725 start
= sWorldSafeLocsStore
.LookupEntry(start2
);
1728 HStartLoc
[0] = start
->x
;
1729 HStartLoc
[1] = start
->y
;
1730 HStartLoc
[2] = start
->z
;
1731 HStartLoc
[3] = fields
[8].GetFloat();
1733 else if (bgTypeID
== BATTLEGROUND_AA
|| bgTypeID
== BATTLEGROUND_ABG
)
1738 HStartLoc
[3] = fields
[8].GetFloat();
1742 sLog
.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID
, start2
);
1746 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1747 if (!CreateBattleGround(bgTypeID
, IsArena
, MinPlayersPerTeam
, MaxPlayersPerTeam
, MinLvl
, MaxLvl
, bl
->name
[sWorld
.GetDefaultDbcLocale()], bl
->mapid
[0], AStartLoc
[0], AStartLoc
[1], AStartLoc
[2], AStartLoc
[3], HStartLoc
[0], HStartLoc
[1], HStartLoc
[2], HStartLoc
[3]))
1751 } while (result
->NextRow());
1756 sLog
.outString( ">> Loaded %u battlegrounds", count
);
1759 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1761 if (sWorld
.getConfig(CONFIG_BOOL_ARENA_AUTO_DISTRIBUTE_POINTS
))
1763 sLog
.outDebug("Initializing Automatic Arena Point Distribution");
1764 QueryResult
* result
= CharacterDatabase
.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1767 sLog
.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1768 m_NextAutoDistributionTime
= time_t(sWorld
.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY
* sWorld
.getConfig(CONFIG_UINT32_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS
));
1769 CharacterDatabase
.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"UI64FMTD
"')", uint64(m_NextAutoDistributionTime
));
1773 m_NextAutoDistributionTime
= time_t((*result
)[0].GetUInt64());
1776 sLog
.outDebug("Automatic Arena Point Distribution initialized.");
1780 void BattleGroundMgr::DistributeArenaPoints()
1782 // used to distribute arena points based on last week's stats
1783 sWorld
.SendWorldText(LANG_DIST_ARENA_POINTS_START
);
1785 sWorld
.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START
);
1787 //temporary structure for storing maximum points to add values for all players
1788 std::map
<uint32
, uint32
> PlayerPoints
;
1790 //at first update all points for all team members
1791 for(ObjectMgr::ArenaTeamMap::iterator team_itr
= sObjectMgr
.GetArenaTeamMapBegin(); team_itr
!= sObjectMgr
.GetArenaTeamMapEnd(); ++team_itr
)
1793 if (ArenaTeam
* at
= team_itr
->second
)
1795 at
->UpdateArenaPointsHelper(PlayerPoints
);
1799 //cycle that gives points to all players
1800 for (std::map
<uint32
, uint32
>::iterator plr_itr
= PlayerPoints
.begin(); plr_itr
!= PlayerPoints
.end(); ++plr_itr
)
1802 //update to database
1803 CharacterDatabase
.PExecute("UPDATE characters SET arenaPoints = arenaPoints + '%u' WHERE guid = '%u'", plr_itr
->second
, plr_itr
->first
);
1804 //add points if player is online
1805 Player
* pl
= sObjectMgr
.GetPlayer(plr_itr
->first
);
1807 pl
->ModifyArenaPoints(plr_itr
->second
);
1810 PlayerPoints
.clear();
1812 sWorld
.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END
);
1814 sWorld
.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START
);
1815 for(ObjectMgr::ArenaTeamMap::iterator titr
= sObjectMgr
.GetArenaTeamMapBegin(); titr
!= sObjectMgr
.GetArenaTeamMapEnd(); ++titr
)
1817 if (ArenaTeam
* at
= titr
->second
)
1819 at
->FinishWeek(); // set played this week etc values to 0 in memory, too
1820 at
->SaveToDB(); // save changes
1821 at
->NotifyStatsChanged(); // notify the players of the changes
1825 sWorld
.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END
);
1827 sWorld
.SendWorldText(LANG_DIST_ARENA_POINTS_END
);
1830 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket
*data
, const uint64
& guid
, Player
* plr
, BattleGroundTypeId bgTypeId
, uint8 fromWhere
)
1835 data
->Initialize(SMSG_BATTLEFIELD_LIST
);
1836 *data
<< uint64(guid
); // battlemaster guid
1837 *data
<< uint8(fromWhere
); // from where you joined
1838 *data
<< uint32(bgTypeId
); // battleground id
1839 if(bgTypeId
== BATTLEGROUND_AA
) // arena
1841 *data
<< uint8(4); // unk
1842 *data
<< uint8(0); // unk
1843 *data
<< uint32(0); // unk (count?)
1845 else // battleground
1847 *data
<< uint8(0); // unk, different for each bg type
1848 *data
<< uint8(0); // unk
1850 size_t count_pos
= data
->wpos();
1852 *data
<< uint32(0); // number of bg instances
1854 if(BattleGround
* bgTemplate
= sBattleGroundMgr
.GetBattleGroundTemplate(bgTypeId
))
1856 // expected bracket entry
1857 if(PvPDifficultyEntry
const* bracketEntry
= GetBattlegroundBracketByLevel(bgTemplate
->GetMapId(),plr
->getLevel()))
1859 BattleGroundBracketId bracketId
= bracketEntry
->GetBracketId();
1860 for(std::set
<uint32
>::iterator itr
= m_ClientBattleGroundIds
[bgTypeId
][bracketId
].begin(); itr
!= m_ClientBattleGroundIds
[bgTypeId
][bracketId
].end();++itr
)
1862 *data
<< uint32(*itr
);
1865 data
->put
<uint32
>( count_pos
, count
);
1871 void BattleGroundMgr::SendToBattleGround(Player
*pl
, uint32 instanceId
, BattleGroundTypeId bgTypeId
)
1873 BattleGround
*bg
= GetBattleGround(instanceId
, bgTypeId
);
1876 uint32 mapid
= bg
->GetMapId();
1878 uint32 team
= pl
->GetBGTeam();
1880 team
= pl
->GetTeam();
1881 bg
->GetTeamStartLoc(team
, x
, y
, z
, O
);
1883 sLog
.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl
->GetName(), mapid
, x
, y
, z
, O
);
1884 pl
->TeleportTo(mapid
, x
, y
, z
, O
);
1888 sLog
.outError("player %u trying to port to non-existent bg instance %u",pl
->GetGUIDLow(), instanceId
);
1892 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId
)
1894 return ( bgTypeId
== BATTLEGROUND_AA
||
1895 bgTypeId
== BATTLEGROUND_BE
||
1896 bgTypeId
== BATTLEGROUND_NA
||
1897 bgTypeId
== BATTLEGROUND_RL
);
1900 BattleGroundQueueTypeId
BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId
, uint8 arenaType
)
1904 case BATTLEGROUND_WS
:
1905 return BATTLEGROUND_QUEUE_WS
;
1906 case BATTLEGROUND_AB
:
1907 return BATTLEGROUND_QUEUE_AB
;
1908 case BATTLEGROUND_AV
:
1909 return BATTLEGROUND_QUEUE_AV
;
1910 case BATTLEGROUND_EY
:
1911 return BATTLEGROUND_QUEUE_EY
;
1912 case BATTLEGROUND_SA
:
1913 return BATTLEGROUND_QUEUE_SA
;
1914 case BATTLEGROUND_IC
:
1915 return BATTLEGROUND_QUEUE_IC
;
1916 case BATTLEGROUND_ABG
:
1917 return BATTLEGROUND_QUEUE_NONE
;
1918 case BATTLEGROUND_AA
:
1919 case BATTLEGROUND_NA
:
1920 case BATTLEGROUND_RL
:
1921 case BATTLEGROUND_BE
:
1922 case BATTLEGROUND_DS
:
1923 case BATTLEGROUND_RV
:
1926 case ARENA_TYPE_2v2
:
1927 return BATTLEGROUND_QUEUE_2v2
;
1928 case ARENA_TYPE_3v3
:
1929 return BATTLEGROUND_QUEUE_3v3
;
1930 case ARENA_TYPE_5v5
:
1931 return BATTLEGROUND_QUEUE_5v5
;
1933 return BATTLEGROUND_QUEUE_NONE
;
1936 return BATTLEGROUND_QUEUE_NONE
;
1940 BattleGroundTypeId
BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId
)
1942 switch(bgQueueTypeId
)
1944 case BATTLEGROUND_QUEUE_WS
:
1945 return BATTLEGROUND_WS
;
1946 case BATTLEGROUND_QUEUE_AB
:
1947 return BATTLEGROUND_AB
;
1948 case BATTLEGROUND_QUEUE_AV
:
1949 return BATTLEGROUND_AV
;
1950 case BATTLEGROUND_QUEUE_EY
:
1951 return BATTLEGROUND_EY
;
1952 case BATTLEGROUND_QUEUE_SA
:
1953 return BATTLEGROUND_SA
;
1954 case BATTLEGROUND_QUEUE_IC
:
1955 return BATTLEGROUND_IC
;
1956 case BATTLEGROUND_QUEUE_2v2
:
1957 case BATTLEGROUND_QUEUE_3v3
:
1958 case BATTLEGROUND_QUEUE_5v5
:
1959 return BATTLEGROUND_AA
;
1961 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
1965 uint8
BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId
)
1967 switch(bgQueueTypeId
)
1969 case BATTLEGROUND_QUEUE_2v2
:
1970 return ARENA_TYPE_2v2
;
1971 case BATTLEGROUND_QUEUE_3v3
:
1972 return ARENA_TYPE_3v3
;
1973 case BATTLEGROUND_QUEUE_5v5
:
1974 return ARENA_TYPE_5v5
;
1980 void BattleGroundMgr::ToggleTesting()
1982 m_Testing
= !m_Testing
;
1984 sWorld
.SendWorldText(LANG_DEBUG_BG_ON
);
1986 sWorld
.SendWorldText(LANG_DEBUG_BG_OFF
);
1989 void BattleGroundMgr::ToggleArenaTesting()
1991 m_ArenaTesting
= !m_ArenaTesting
;
1993 sWorld
.SendWorldText(LANG_DEBUG_ARENA_ON
);
1995 sWorld
.SendWorldText(LANG_DEBUG_ARENA_OFF
);
1998 void BattleGroundMgr::ScheduleQueueUpdate(uint32 arenaRating
, uint8 arenaType
, BattleGroundQueueTypeId bgQueueTypeId
, BattleGroundTypeId bgTypeId
, BattleGroundBracketId bracket_id
)
2000 //ACE_Guard<ACE_Thread_Mutex> guard(SchedulerLock);
2001 //we will use only 1 number created of bgTypeId and bracket_id
2002 uint64 schedule_id
= ((uint64
)arenaRating
<< 32) | (arenaType
<< 24) | (bgQueueTypeId
<< 16) | (bgTypeId
<< 8) | bracket_id
;
2004 for (uint8 i
= 0; i
< m_QueueUpdateScheduler
.size(); i
++)
2006 if (m_QueueUpdateScheduler
[i
] == schedule_id
)
2013 m_QueueUpdateScheduler
.push_back(schedule_id
);
2016 uint32
BattleGroundMgr::GetMaxRatingDifference() const
2018 // this is for stupid people who can't use brain and set max rating difference to 0
2019 uint32 diff
= sWorld
.getConfig(CONFIG_UINT32_ARENA_MAX_RATING_DIFFERENCE
);
2025 uint32
BattleGroundMgr::GetRatingDiscardTimer() const
2027 return sWorld
.getConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER
);
2030 uint32
BattleGroundMgr::GetPrematureFinishTime() const
2032 return sWorld
.getConfig(CONFIG_UINT32_BATTLEGROUND_PREMATURE_FINISH_TIMER
);
2035 void BattleGroundMgr::LoadBattleMastersEntry()
2037 mBattleMastersMap
.clear(); // need for reload case
2039 QueryResult
*result
= WorldDatabase
.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
2049 sLog
.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
2053 barGoLink
bar( (int)result
->GetRowCount() );
2060 Field
*fields
= result
->Fetch();
2062 uint32 entry
= fields
[0].GetUInt32();
2063 uint32 bgTypeId
= fields
[1].GetUInt32();
2064 if (!sBattlemasterListStore
.LookupEntry(bgTypeId
))
2066 sLog
.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry
,bgTypeId
);
2070 mBattleMastersMap
[entry
] = BattleGroundTypeId(bgTypeId
);
2072 } while( result
->NextRow() );
2077 sLog
.outString( ">> Loaded %u battlemaster entries", count
);
2080 bool BattleGroundMgr::IsBGWeekend(BattleGroundTypeId bgTypeId
)
2084 case BATTLEGROUND_AV
:
2085 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_AV
);
2086 case BATTLEGROUND_EY
:
2087 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_EY
);
2088 case BATTLEGROUND_WS
:
2089 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_WS
);
2090 case BATTLEGROUND_SA
:
2091 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_SA
);
2097 void BattleGroundMgr::LoadBattleEventIndexes()
2099 BattleGroundEventIdx events
;
2100 events
.event1
= BG_EVENT_NONE
;
2101 events
.event2
= BG_EVENT_NONE
;
2102 m_GameObjectBattleEventIndexMap
.clear(); // need for reload case
2103 m_GameObjectBattleEventIndexMap
[-1] = events
;
2104 m_CreatureBattleEventIndexMap
.clear(); // need for reload case
2105 m_CreatureBattleEventIndexMap
[-1] = events
;
2109 QueryResult
*result
=
2111 WorldDatabase
.PQuery( "SELECT data.typ, data.guid1, data.ev1 AS ev1, data.ev2 AS ev2, data.map AS m, data.guid2, description.map, "
2113 "description.event1, description.event2, description.description "
2115 "(SELECT '1' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2116 "FROM gameobject_battleground AS a "
2117 "LEFT OUTER JOIN gameobject AS b ON a.guid = b.guid "
2119 "SELECT '2' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2120 "FROM creature_battleground AS a "
2121 "LEFT OUTER JOIN creature AS b ON a.guid = b.guid "
2123 "RIGHT OUTER JOIN battleground_events AS description ON data.map = description.map "
2124 "AND data.ev1 = description.event1 AND data.ev2 = description.event2 "
2125 // full outer join doesn't work in mysql :-/ so just UNION-select the same again and add a left outer join
2127 "SELECT data.typ, data.guid1, data.ev1, data.ev2, data.map, data.guid2, description.map, "
2128 "description.event1, description.event2, description.description "
2130 "(SELECT '1' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2131 "FROM gameobject_battleground AS a "
2132 "LEFT OUTER JOIN gameobject AS b ON a.guid = b.guid "
2134 "SELECT '2' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2135 "FROM creature_battleground AS a "
2136 "LEFT OUTER JOIN creature AS b ON a.guid = b.guid "
2138 "LEFT OUTER JOIN battleground_events AS description ON data.map = description.map "
2139 "AND data.ev1 = description.event1 AND data.ev2 = description.event2 "
2140 "ORDER BY m, ev1, ev2" );
2147 sLog
.outErrorDb(">> Loaded 0 battleground eventindexes.");
2151 barGoLink
bar((int)result
->GetRowCount());
2156 Field
*fields
= result
->Fetch();
2157 if (fields
[2].GetUInt8() == BG_EVENT_NONE
|| fields
[3].GetUInt8() == BG_EVENT_NONE
)
2158 continue; // we don't need to add those to the eventmap
2160 bool gameobject
= (fields
[0].GetUInt8() == 1);
2161 uint32 dbTableGuidLow
= fields
[1].GetUInt32();
2162 events
.event1
= fields
[2].GetUInt8();
2163 events
.event2
= fields
[3].GetUInt8();
2164 uint32 map
= fields
[4].GetUInt32();
2166 uint32 desc_map
= fields
[6].GetUInt32();
2167 uint8 desc_event1
= fields
[7].GetUInt8();
2168 uint8 desc_event2
= fields
[8].GetUInt8();
2169 const char *description
= fields
[9].GetString();
2171 // checking for NULL - through right outer join this will mean following:
2172 if (fields
[5].GetUInt32() != dbTableGuidLow
)
2174 sLog
.outErrorDb("BattleGroundEvent: %s with nonexistant guid %u for event: map:%u, event1:%u, event2:%u (\"%s\")",
2175 (gameobject
) ? "gameobject" : "creature", dbTableGuidLow
, map
, events
.event1
, events
.event2
, description
);
2179 // checking for NULL - through full outer join this can mean 2 things:
2180 if (desc_map
!= map
)
2182 // there is an event missing
2183 if (dbTableGuidLow
== 0)
2185 sLog
.outErrorDb("BattleGroundEvent: missing db-data for map:%u, event1:%u, event2:%u (\"%s\")", desc_map
, desc_event1
, desc_event2
, description
);
2188 // we have an event which shouldn't exist
2191 sLog
.outErrorDb("BattleGroundEvent: %s with guid %u is registered, for a nonexistant event: map:%u, event1:%u, event2:%u",
2192 (gameobject
) ? "gameobject" : "creature", dbTableGuidLow
, map
, events
.event1
, events
.event2
);
2198 m_GameObjectBattleEventIndexMap
[dbTableGuidLow
] = events
;
2200 m_CreatureBattleEventIndexMap
[dbTableGuidLow
] = events
;
2204 } while(result
->NextRow());
2207 sLog
.outString( ">> Loaded %u battleground eventindexes", count
);