OregonCore  revision 3611e8a-git
Your Favourite TBC server
BattlegroundMgr.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "Common.h"
19 #include "Player.h"
20 #include "BattlegroundMgr.h"
21 #include "BattlegroundAV.h"
22 #include "BattlegroundAB.h"
23 #include "BattlegroundEY.h"
24 #include "BattlegroundWS.h"
25 #include "BattlegroundNA.h"
26 #include "BattlegroundBE.h"
27 #include "BattlegroundAA.h"
28 #include "BattlegroundRL.h"
29 #include "SharedDefines.h"
30 #include "MapManager.h"
31 #include "Map.h"
32 #include "ObjectMgr.h"
33 #include "World.h"
34 #include "Chat.h"
35 #include "ArenaTeam.h"
36 #include "DisableMgr.h"
37 
39 
40 /*********************************************************/
41 /*** BATTLEGROUND QUEUE SYSTEM ***/
42 /*********************************************************/
43 
45 {
46  //queues are empty, we don't have to call clear()
47  /* for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
48  {
49  //m_QueuedPlayers[i].Horde = 0;
50  //m_QueuedPlayers[i].Alliance = 0;
51  //m_QueuedPlayers[i].AverageTime = 0;
52  }*/
53 }
54 
56 {
57  for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
58  {
59  m_QueuedPlayers[i].clear();
60  for (QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr != m_QueuedGroups[i].end(); ++itr)
61  delete (*itr);
62  m_QueuedGroups[i].clear();
63  }
64 }
65 
66 // initialize eligible groups from the given source matching the given specifications
67 void BattlegroundQueue::EligibleGroups::Init(BattlegroundQueue::QueuedGroupsList* source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType, bool IsRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam)
68 {
69  // clear from prev initialization
70  clear();
71  BattlegroundQueue::QueuedGroupsList::iterator itr, next;
72  // iterate through the source
73  for (itr = source->begin(); itr != source->end(); itr = next)
74  {
75  next = itr;
76  ++next;
77  if ((*itr)->BgTypeId == BgTypeId && // bg type must match
78  (*itr)->ArenaType == ArenaType && // arena type must match
79  (*itr)->IsRated == IsRated && // israted must match
80  (*itr)->IsInvitedToBGInstanceGUID == 0 && // leave out already invited groups
81  (*itr)->Team == side && // match side
82  (*itr)->Players.size() <= MaxPlayers && // the group must fit in the bg
83  (!excludeTeam || (*itr)->ArenaTeamId != excludeTeam) && // if excludeTeam is specified, leave out those arena team ids
84  (!IsRated || (*itr)->Players.size() == MaxPlayers) && // if rated, then pass only if the player count is exact NEEDS TESTING! (but now this should never happen)
85  (!DisregardTime || (*itr)->JoinTime <= DisregardTime // pass if disregard time is greater than join time
86  || (*itr)->ArenaTeamRating == 0 // pass if no rating info
87  || ((*itr)->ArenaTeamRating >= MinRating // pass if matches the rating range
88  && (*itr)->ArenaTeamRating <= MaxRating)))
89  {
90  // the group matches the conditions
91  // using push_back for proper selecting when inviting
92  push_back((*itr));
93  }
94  }
95 }
96 
97 // selection pool initialization, used to clean up from prev selection
99 {
100  m_CurrEligGroups = curr;
101  SelectedGroups.clear();
102  PlayerCount = 0;
103 }
104 
105 // remove group info from selection pool
107 {
108  // find what to remove
109  for (std::list<GroupQueueInfo*>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
110  {
111  if ((*itr) == ginfo)
112  {
113  SelectedGroups.erase(itr);
114  // decrease selected players count
115  PlayerCount -= ginfo->Players.size();
116  return;
117  }
118  }
119 }
120 
121 // add group to selection
122 // used when building selection pools
124 {
125  SelectedGroups.push_back(ginfo);
126  // increase selected players count
127  PlayerCount += ginfo->Players.size();
128 }
129 
130 // add group to bg queue with the given leader and bg specifications
131 GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating, uint32 arenateamid)
132 {
133  uint32 queue_id = leader->GetBattlegroundQueueIdFromLevel();
134 
135  // create new ginfo
136  // cannot use the method like in addplayer, because that could modify an in-queue group's stats
137  // (e.g. leader leaving queue then joining as individual again)
138  GroupQueueInfo* ginfo = new GroupQueueInfo;
139  ginfo->BgTypeId = BgTypeId;
140  ginfo->ArenaType = ArenaType;
141  ginfo->ArenaTeamId = arenateamid;
142  ginfo->IsRated = isRated;
143  ginfo->IsInvitedToBGInstanceGUID = 0; // maybe this should be modifiable by function arguments to enable selection of running instances?
144  ginfo->JoinTime = getMSTime();
145  ginfo->Team = leader->GetTeam();
146  ginfo->ArenaTeamRating = arenaRating;
147  ginfo->OpponentsTeamRating = 0; //initialize it to 0
148 
149  ginfo->Players.clear();
150 
151  m_QueuedGroups[queue_id].push_back(ginfo);
152 
153  // return ginfo, because it is needed to add players to this group info
154  return ginfo;
155 }
156 
158 {
159  uint32 queue_id = plr->GetBattlegroundQueueIdFromLevel();
160 
161  //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
162  PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()];
163  info.InviteTime = 0;
164  info.LastInviteTime = 0;
165  info.LastOnlineTime = getMSTime();
166  info.GroupInfo = ginfo;
167 
168  // add the pinfo to ginfo's list
169  ginfo->Players[plr->GetGUID()] = &info;
170 
172  {
173  //announce only once in a time
174  if (!sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY) && m_QueuedPlayers[queue_id].size() % 5 != 0) return;
175  Battleground* bg = sBattlegroundMgr.GetBattlegroundTemplate(ginfo->BgTypeId);
176  if (!bg) return;
177 
178  char const* bgName = bg->GetName();
179 
180  uint32 q_min_level = Player::GetMinLevelForBattlegroundQueueId(queue_id);
181  uint32 q_max_level = Player::GetMaxLevelForBattlegroundQueueId(queue_id);
182 
183  // replace hardcoded max level by player max level for nice output
184  if (q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
185  q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
186 
187  uint32 MinPlayers = bg->GetMinPlayersPerTeam();
188  uint32 MaxPlayers = bg->GetMaxPlayersPerTeam();
189 
190  uint32 qHorde = 0;
191  uint32 qAlliance = 0;
192 
193  for (std::map<uint64, PlayerQueueInfo>::iterator itr = m_QueuedPlayers[queue_id].begin(); itr != m_QueuedPlayers[queue_id].end(); ++itr)
194  {
195  Player* _player = sObjectMgr.GetPlayer((uint64)itr->first);
196  if (_player)
197  {
198  if (_player->GetTeam() == ALLIANCE)
199  qAlliance++;
200  else
201  qHorde++;
202  }
203  }
204 
205  // Show queue status to player only (when joining queue)
207  {
208  uint32 needAlliance = (MinPlayers < qAlliance) ? 0 : MinPlayers - qAlliance;
209  uint32 needHorde = (MinPlayers < qHorde) ? 0 : MinPlayers - qHorde;
211  bgName, q_min_level, q_max_level, qAlliance, needAlliance, qHorde, needHorde);
212  }
213  // System message
214  else
215  {
216  sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
217  bgName, q_min_level, q_max_level, qAlliance, MaxPlayers, qHorde, MaxPlayers);
218  }
219  }
220 }
221 
222 void BattlegroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
223 {
224  Player* plr = sObjectMgr.GetPlayer(guid);
225 
226  int32 queue_id = 0; // signed for proper for-loop finish
227  QueuedPlayersMap::iterator itr;
228  GroupQueueInfo* group;
229  QueuedGroupsList::iterator group_itr;
230  bool IsSet = false;
231  if (plr)
232  {
233  queue_id = plr->GetBattlegroundQueueIdFromLevel();
234 
235  itr = m_QueuedPlayers[queue_id].find(guid);
236  if (itr != m_QueuedPlayers[queue_id].end())
237  IsSet = true;
238  }
239 
240  if (!IsSet)
241  {
242  // either player is offline, or he levelled up to another queue category
243  // sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");
244  for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
245  {
246  itr = m_QueuedPlayers[i].find(guid);
247  if (itr != m_QueuedPlayers[i].end())
248  {
249  queue_id = i;
250  IsSet = true;
251  break;
252  }
253  }
254  }
255 
256  // couldn't find the player in bg queue, return
257  if (!IsSet)
258  {
259  sLog.outError("Battleground: couldn't find player to remove.");
260  return;
261  }
262 
263  group = itr->second.GroupInfo;
264 
265  for (group_itr = m_QueuedGroups[queue_id].begin(); group_itr != m_QueuedGroups[queue_id].end(); ++group_itr)
266  {
267  if (group == (GroupQueueInfo*)(*group_itr))
268  break;
269  }
270 
271  // variables are set (what about leveling up when in queue????)
272  // remove player from group
273  // if only player there, remove group
274 
275  // remove player queue info from group queue info
276  std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
277 
278  if (pitr != group->Players.end())
279  group->Players.erase(pitr);
280 
281  // check for iterator correctness
282  if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())
283  {
284  // used when player left the queue, NOT used when porting to bg
285  if (decreaseInvitedCount)
286  {
287  // if invited to bg, and should decrease invited count, then do it
288  if (group->IsInvitedToBGInstanceGUID)
289  {
290  Battleground* bg = sBattlegroundMgr.GetBattleground(group->IsInvitedToBGInstanceGUID);
291  if (bg)
292  bg->DecreaseInvitedCount(group->Team);
293  if (bg && !bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE))
294  {
295  // no more players on battleground, set delete it
296  bg->SetDeleteThis();
297  }
298  }
299  // update the join queue, maybe now the player's group fits in a queue!
300  // not yet implemented (should store bgTypeId in group queue info?)
301  }
302  //if player leaves queue and he is invited to rated arena match, then he has to loose
303  if (group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount)
304  {
305  ArenaTeam* at = sObjectMgr.GetArenaTeamById(group->ArenaTeamId);
306  if (at)
307  {
308  sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating);
309  Player* plr = sObjectMgr.GetPlayer(guid);
310  if (plr)
311  at->MemberLost(plr, group->OpponentsTeamRating);
312  else
313  at->OfflineMemberLost(guid, group->OpponentsTeamRating);
314  at->SaveToDB();
315  }
316  }
317  // remove player queue info
318  m_QueuedPlayers[queue_id].erase(itr);
319  // remove group queue info if needed
320  if (group->Players.empty())
321  {
322  m_QueuedGroups[queue_id].erase(group_itr);
323  delete group;
324  }
325  // NEEDS TESTING!
326  // group wasn't empty, so it wasn't deleted, and player have left a rated queue -> everyone from the group should leave too
327  // don't remove recursively if already invited to bg!
328  else if (!group->IsInvitedToBGInstanceGUID && decreaseInvitedCount && group->IsRated)
329  {
330  // remove next player, this is recursive
331  // first send removal information
332  if (Player* plr2 = sObjectMgr.GetPlayer(group->Players.begin()->first))
333  {
334  Battleground* bg = sBattlegroundMgr.GetBattlegroundTemplate(group->BgTypeId);
335  uint32 bgQueueTypeId = sBattlegroundMgr.BGQueueTypeId(group->BgTypeId, group->ArenaType);
336  uint32 queueSlot = plr2->GetBattlegroundQueueIndex(bgQueueTypeId);
337  plr2->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
338  WorldPacket data;
339  sBattlegroundMgr.BuildBattlegroundStatusPacket(&data, bg, plr2->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
340  plr2->GetSession()->SendPacket(&data);
341  }
342  // then actually delete, this may delete the group as well!
343  RemovePlayer(group->Players.begin()->first, decreaseInvitedCount);
344  }
345  }
346 }
347 
349 {
350  // set side if needed
351  if (side)
352  ginfo->Team = side;
353 
354  if (!ginfo->IsInvitedToBGInstanceGUID)
355  {
356  // not yet invited
357  // set invitation
359  uint32 bgQueueTypeId = sBattlegroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
360  // loop through the players
361  for (std::map<uint64, PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
362  {
363  // set status
364  itr->second->InviteTime = getMSTime();
365  itr->second->LastInviteTime = getMSTime();
366 
367  // get the player
368  Player* plr = sObjectMgr.GetPlayer(itr->first, true);
369  // if offline, skip him
370  if (!plr)
371  continue;
372 
373  // invite the player
374  sBattlegroundMgr.InvitePlayer(plr, bg->GetInstanceID(), ginfo->Team);
375 
376  WorldPacket data;
377 
378  uint32 queueSlot = plr->GetBattlegroundQueueIndex(bgQueueTypeId);
379 
380  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());
381 
382  // send status packet
383  sBattlegroundMgr.BuildBattlegroundStatusPacket(&data, bg, side ? side : plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
384  plr->GetSession()->SendPacket(&data);
385  }
386  return true;
387  }
388 
389  return false;
390 }
391 
392 // used to recursively select groups from eligible groups
393 bool BattlegroundQueue::SelectionPool::Build(uint32 MinPlayers, uint32 MaxPlayers, EligibleGroups::iterator startitr)
394 {
395  // start from the specified start iterator
396  for (EligibleGroups::iterator itr1 = startitr; itr1 != m_CurrEligGroups->end(); ++itr1)
397  {
398  // if it fits in, select it
399  if (GetPlayerCount() + (*itr1)->Players.size() <= MaxPlayers)
400  {
401  EligibleGroups::iterator next = itr1;
402  ++next;
403  AddGroup((*itr1));
404  if (GetPlayerCount() >= MinPlayers)
405  {
406  // enough players are selected
407  return true;
408  }
409  // try building from the rest of the elig. groups
410  // if that succeeds, return true
411  if (Build(MinPlayers, MaxPlayers, next))
412  return true;
413  // the rest didn't succeed, so this group cannot be included
414  RemoveGroup((*itr1));
415  }
416  }
417  // build didn't succeed
418  return false;
419 }
420 
421 // this function is responsible for the selection of queued groups when trying to create new battlegrounds
422 bool BattlegroundQueue::BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType, bool isRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam)
423 {
424  uint32 side;
425  switch (mode)
426  {
427  case NORMAL_ALLIANCE:
430  side = ALLIANCE;
431  break;
432  case NORMAL_HORDE:
433  case ONESIDE_HORDE_TEAM1:
434  case ONESIDE_HORDE_TEAM2:
435  side = HORDE;
436  break;
437  default:
438  //unknown mode, return false
439  sLog.outDebug("Battleground: unknown selection pool build mode, returning...");
440  return false;
441  break;
442  }
443 
444  // initiate the groups eligible to create the bg
445  m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime, excludeTeam);
446  // init the selected groups (clear)
447  // and set m_CurrEligGroups pointer
448  // we set it this way to only have one EligibleGroups object to save some memory
450  // build succeeded
451  if (m_SelectionPools[mode].Build(MinPlayers, MaxPlayers, m_EligibleGroups.begin()))
452  {
453  // the selection pool is set, return
454  sLog.outDebug("Battleground-debug: pool build succeeded, return true");
455  sLog.outDebug("Battleground-debug: Player size for mode %u is %u", mode, m_SelectionPools[mode].GetPlayerCount());
456  for (std::list<GroupQueueInfo* >::iterator itr = m_SelectionPools[mode].SelectedGroups.begin(); itr != m_SelectionPools[mode].SelectedGroups.end(); ++itr)
457  {
458  sLog.outDebug("Battleground-debug: queued group in selection with %lu players", (*itr)->Players.size());
459  for (std::map<uint64, PlayerQueueInfo* >::iterator itr2 = (*itr)->Players.begin(); itr2 != (*itr)->Players.end(); ++itr2)
460  sLog.outDebug("Battleground-debug: player in above group GUID %u", (uint32)(itr2->first));
461  }
462  return true;
463  }
464  // failed to build a selection pool matching the given values
465  return false;
466 }
467 
468 // used to remove the Enter Battle window if the battle has already, but someone still has it
469 // (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event
471 {
472  uint32 queue_id = bg->GetQueueType();
473  uint32 bgInstanceId = bg->GetInstanceID();
474  uint32 bgQueueTypeId = sBattlegroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
475  QueuedGroupsList::iterator itr, next;
476  for (itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next)
477  {
478  // must do this way, because the groupinfo will be deleted when all playerinfos are removed
479  GroupQueueInfo* ginfo = (*itr);
480  next = itr;
481  ++next;
482  // if group was invited to this bg instance, then remove all references
483  if (ginfo->IsInvitedToBGInstanceGUID == bgInstanceId)
484  {
485  // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop
486  uint32 to_remove = ginfo->Players.size();
487  uint32 team = ginfo->Team;
488  for (uint32 i = 0; i < to_remove; ++i)
489  {
490  // always remove the first one in the group
491  std::map<uint64, PlayerQueueInfo* >::iterator itr2 = ginfo->Players.begin();
492  if (itr2 == ginfo->Players.end())
493  {
494  sLog.outError("Empty Players in ginfo, this should never happen!");
495  return;
496  }
497 
498  // get the player
499  Player* plr = sObjectMgr.GetPlayer(itr2->first);
500  if (!plr)
501  {
502  sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");
503  continue;
504  }
505 
506  // get the queueslot
507  uint32 queueSlot = plr->GetBattlegroundQueueIndex(bgQueueTypeId);
508  if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
509  {
510  plr->RemoveBattlegroundQueueId(bgQueueTypeId);
511  // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
512  RemovePlayer(itr2->first, true);
513  // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups
514  // but updating the queue can't hurt
515  Update(bgQueueTypeId, bg->GetQueueType());
516  // send info to client
517  WorldPacket data;
518  sBattlegroundMgr.BuildBattlegroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0);
519  plr->GetSession()->SendPacket(&data);
520  }
521  }
522  }
523  }
524 }
525 
526 /*
527 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
528 it must be called after fully adding the members of a group to ensure group joining
529 should be called after removeplayer functions in some cases
530 */
531 void BattlegroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating)
532 {
533  if (queue_id >= MAX_BATTLEGROUND_QUEUES)
534  {
535  //this is error, that caused crashes (not in , but now it shouldn't)
536  sLog.outError("BattlegroundQueue::Update() called for invalid queue type - this can cause crash, pls report problem, if this is the last line of error log before crash");
537  return;
538  }
539 
540  //if no players in queue ... do nothing
541  if (m_QueuedGroups[queue_id].empty())
542  return;
543 
544  //battleground with free slot for player should be always the last in this queue
545  BGFreeSlotQueueType::iterator itr, next;
546  for (itr = sBattlegroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattlegroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
547  {
548  next = itr;
549  ++next;
550  // battleground is running, so if:
551  // DO NOT allow queue manager to invite new player to running arena
552  if ((*itr)->isBattleground() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
553  {
554  //we must check both teams
555  Battleground* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
556  // and iterator is invalid
557 
558  for (QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr)
559  {
560  // did the group join for this bg type?
561  if ((*itr)->BgTypeId != bgTypeId)
562  continue;
563  // if so, check if fits in
564  if (bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size())
565  {
566  // if group fits in, invite it
567  InviteGroupToBG((*itr), bg, (*itr)->Team);
568  }
569  }
570 
571  if (!bg->HasFreeSlots())
572  {
573  //remove BG from BGFreeSlotQueue
575  }
576  }
577  }
578 
579  // finished iterating through the bgs with free slots, maybe we need to create a new bg
580 
581  Battleground* bg_template = sBattlegroundMgr.GetBattlegroundTemplate(bgTypeId);
582  if (!bg_template)
583  {
584  sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
585  return;
586  }
587 
588  // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
589  uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
590  uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
591  if (bg_template->isArena())
592  {
593  if (sBattlegroundMgr.isArenaTesting())
594  {
595  MaxPlayersPerTeam = 1;
596  MinPlayersPerTeam = 1;
597  }
598  else
599  {
600  switch (arenatype)
601  {
602  case ARENA_TYPE_2v2:
603  MaxPlayersPerTeam = 2;
604  MinPlayersPerTeam = 2;
605  break;
606  case ARENA_TYPE_3v3:
607  MaxPlayersPerTeam = 3;
608  MinPlayersPerTeam = 3;
609  break;
610  case ARENA_TYPE_5v5:
611  MaxPlayersPerTeam = 5;
612  MinPlayersPerTeam = 5;
613  break;
614  }
615  }
616  }
617  else
618  {
619  if (sBattlegroundMgr.isTesting())
620  MinPlayersPerTeam = 1;
621  }
622 
623  // found out the minimum and maximum ratings the newly added team should battle against
624  // arenaRating is the rating of the latest joined team
625  uint32 arenaMinRating = (arenaRating <= sBattlegroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattlegroundMgr.GetMaxRatingDifference();
626  // if no rating is specified, set maxrating to 0
627  uint32 arenaMaxRating = (arenaRating == 0) ? 0 : arenaRating + sBattlegroundMgr.GetMaxRatingDifference();
628  uint32 discardTime = 0;
629  // if max rating difference is set and the time past since server startup is greater than the rating discard time
630  // (after what time the ratings aren't taken into account when making teams) then
631  // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
632  // else leave the discard time on 0, this way all ratings will be discarded
633  if (sBattlegroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattlegroundMgr.GetRatingDiscardTimer())
634  discardTime = getMSTime() - sBattlegroundMgr.GetRatingDiscardTimer();
635 
636  // try to build the selection pools
637  bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
638  if (bAllyOK)
639  sLog.outDebug("Battleground: ally pool successfully built");
640  else
641  sLog.outDebug("Battleground: ally pool wasn't created");
642  bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
643  if (bHordeOK)
644  sLog.outDebug("Battleground: horde pool successfully built");
645  else
646  sLog.outDebug("Battleground: horde pool wasn't created");
647 
648  // if selection pools are ready, create the new bg
649  if ((bAllyOK && bHordeOK) || (sBattlegroundMgr.isTesting() && (bAllyOK || bHordeOK)))
650  {
651  Battleground* bg2 = 0;
652  // special handling for arenas
653  if (bg_template->isArena())
654  {
655  // Find a random arena, that can be created
657  uint32 arena_num = urand(0, 2);
658  if (!(bg2 = sBattlegroundMgr.CreateNewBattleground(arenas[arena_num % 3], arenatype, isRated)) &&
659  !(bg2 = sBattlegroundMgr.CreateNewBattleground(arenas[(arena_num + 1) % 3], arenatype, isRated)) &&
660  !(bg2 = sBattlegroundMgr.CreateNewBattleground(arenas[(arena_num + 2) % 3], arenatype, isRated)))
661  {
662  sLog.outError("Battleground: couldn't create any arena instance!");
663  return;
664  }
665 
666  // set the MaxPlayersPerTeam values based on arenatype
667  // setting the min player values isn't needed, since we won't be using that value later on.
668  if (sBattlegroundMgr.isArenaTesting())
669  {
670  bg2->SetMaxPlayersPerTeam(1);
671  bg2->SetMaxPlayers(2);
672  }
673  else
674  {
675  switch (arenatype)
676  {
677  case ARENA_TYPE_2v2:
678  bg2->SetMaxPlayersPerTeam(2);
679  bg2->SetMaxPlayers(4);
680  break;
681  case ARENA_TYPE_3v3:
682  bg2->SetMaxPlayersPerTeam(3);
683  bg2->SetMaxPlayers(6);
684  break;
685  case ARENA_TYPE_5v5:
686  bg2->SetMaxPlayersPerTeam(5);
687  bg2->SetMaxPlayers(10);
688  break;
689  default:
690  break;
691  }
692  }
693  }
694  else
695  {
696  // create new battleground
697  bg2 = sBattlegroundMgr.CreateNewBattleground(bgTypeId, arenatype, false);
698  }
699 
700  if (!bg2)
701  {
702  sLog.outError("Battleground: couldn't create bg %u", bgTypeId);
703  return;
704  }
705 
706  bg2->SetQueueType(queue_id);
707 
708  std::list<GroupQueueInfo* >::iterator itr;
709 
710  // Send amount of invites based on the difference between the sizes of the two faction's queues
711  uint32 QUEUED_HORDE = m_SelectionPools[NORMAL_HORDE].SelectedGroups.size();
712  uint32 QUEUED_ALLIANCE = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.size();
713  uint16 maxbginvites = 0;
714 
715  if (QUEUED_ALLIANCE <= QUEUED_HORDE)
716  maxbginvites = QUEUED_ALLIANCE;
717  else
718  maxbginvites = QUEUED_HORDE;
719 
720  // invite groups from horde selection pool
721  uint16 invitecounter = 0;
722  for (itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr)
723  {
724  if (invitecounter >= maxbginvites)
725  return;
726  InviteGroupToBG((*itr), bg2, HORDE);
727  ++invitecounter;
728  }
729 
730  // invite groups from ally selection pool
731  invitecounter = 0;
732  for (itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)
733  {
734  if (invitecounter >= maxbginvites)
735  return;
736  InviteGroupToBG((*itr), bg2, ALLIANCE);
737  ++invitecounter;
738  }
739 
740  if (isRated)
741  {
742  std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin();
743  std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin();
744  (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
745  sLog.outDebug("setting opposite team rating for team %u to %u", (*itr_alliance)->ArenaTeamId, (*itr_alliance)->OpponentsTeamRating);
746  (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
747  sLog.outDebug("setting opposite team rating for team %u to %u", (*itr_horde)->ArenaTeamId, (*itr_horde)->OpponentsTeamRating);
748  }
749 
750  // start the battleground
751  bg2->StartBattleground();
752  }
753 
754  // there weren't enough players for a "normal" match
755  // if arena, enable horde versus horde or alliance versus alliance teams here
756 
757  else if (bg_template->isArena())
758  {
759  bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false;
760  bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false;
761  bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id, MaxPlayersPerTeam, MaxPlayersPerTeam, ONESIDE_HORDE_TEAM1, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
762  if (bOneSideHordeTeam1)
763  {
764  // one team has been selected, find out if other can be selected too
765  std::list<GroupQueueInfo* >::iterator itr;
766  // temporarily change the team side to enable building the next pool excluding the already selected groups
767  for (itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
768  (*itr)->Team = ALLIANCE;
769 
770  bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id, MaxPlayersPerTeam, MaxPlayersPerTeam, ONESIDE_HORDE_TEAM2, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime, (*(m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
771 
772  // change back the team to horde
773  for (itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
774  (*itr)->Team = HORDE;
775 
776  if (!bOneSideHordeTeam2)
777  bOneSideHordeTeam1 = false;
778  }
779  if (!bOneSideHordeTeam1)
780  {
781  // check for one sided ally
782  bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id, MaxPlayersPerTeam, MaxPlayersPerTeam, ONESIDE_ALLIANCE_TEAM1, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
783  if (bOneSideAllyTeam1)
784  {
785  // one team has been selected, find out if other can be selected too
786  std::list<GroupQueueInfo* >::iterator itr;
787  // temporarily change the team side to enable building the next pool excluding the already selected groups
788  for (itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
789  (*itr)->Team = HORDE;
790 
791  bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id, MaxPlayersPerTeam, MaxPlayersPerTeam, ONESIDE_ALLIANCE_TEAM2, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime, (*(m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
792 
793  // change back the team to ally
794  for (itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
795  (*itr)->Team = ALLIANCE;
796  }
797 
798  if (!bOneSideAllyTeam2)
799  bOneSideAllyTeam1 = false;
800  }
801  // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!
802  if ((bOneSideHordeTeam1 && bOneSideHordeTeam2) ||
803  (bOneSideAllyTeam1 && bOneSideAllyTeam2))
804  {
805  // which side has enough players?
806  SelectionPoolBuildMode mode1, mode2;
807  // find out what pools are we using
808  if (bOneSideAllyTeam1 && bOneSideAllyTeam2)
809  {
810  mode1 = ONESIDE_ALLIANCE_TEAM1;
811  mode2 = ONESIDE_ALLIANCE_TEAM2;
812  }
813  else
814  {
815  mode1 = ONESIDE_HORDE_TEAM1;
816  mode2 = ONESIDE_HORDE_TEAM2;
817  }
818 
819  // create random arena
821  uint32 arena_num = urand(0, 2);
822  Battleground* bg2 = NULL;
823  if (!(bg2 = sBattlegroundMgr.CreateNewBattleground(arenas[arena_num % 3], arenatype, isRated)) &&
824  !(bg2 = sBattlegroundMgr.CreateNewBattleground(arenas[(arena_num + 1) % 3], arenatype, isRated)) &&
825  !(bg2 = sBattlegroundMgr.CreateNewBattleground(arenas[(arena_num + 2) % 3], arenatype, isRated)))
826  {
827  sLog.outError("Could not create arena.");
828  return;
829  }
830 
831  sLog.outDebug("Battleground: One-faction arena created.");
832  // init stats
833  if (sBattlegroundMgr.isArenaTesting())
834  {
835  bg2->SetMaxPlayersPerTeam(1);
836  bg2->SetMaxPlayers(2);
837  }
838  else
839  {
840  switch (arenatype)
841  {
842  case ARENA_TYPE_2v2:
843  bg2->SetMaxPlayersPerTeam(2);
844  bg2->SetMaxPlayers(4);
845  break;
846  case ARENA_TYPE_3v3:
847  bg2->SetMaxPlayersPerTeam(3);
848  bg2->SetMaxPlayers(6);
849  break;
850  case ARENA_TYPE_5v5:
851  bg2->SetMaxPlayersPerTeam(5);
852  bg2->SetMaxPlayers(10);
853  break;
854  default:
855  break;
856  }
857  }
858 
859  bg2->SetQueueType(queue_id);
860 
861  std::list<GroupQueueInfo* >::iterator itr;
862 
863  // invite players from the first group as horde players (actually green team)
864  for (itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr)
865  InviteGroupToBG((*itr), bg2, HORDE);
866 
867  // invite players from the second group as ally players (actually gold team)
868  for (itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr)
869  InviteGroupToBG((*itr), bg2, ALLIANCE);
870 
871  if (isRated)
872  {
873  std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[mode1].SelectedGroups.begin();
874  std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[mode2].SelectedGroups.begin();
875  (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
876  (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
877  }
878 
879  bg2->StartBattleground();
880  }
881  }
882 }
883 
884 /*********************************************************/
885 /*** BATTLEGROUND QUEUE EVENTS ***/
886 /*********************************************************/
887 
888 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
889 {
890  Player* plr = sObjectMgr.GetPlayer(m_PlayerGuid);
891 
892  // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
893  if (!plr)
894  return true;
895 
896  // Player can be in another BG queue and must be removed in normal way in any case
897  // // player is already in battleground ... do nothing (battleground queue status is deleted when player is teleported to BG)
898  // if (plr->GetBattlegroundId() > 0)
899  // return true;
900 
901  Battleground* bg = sBattlegroundMgr.GetBattleground(m_BgInstanceGUID);
902  if (!bg)
903  return true;
904 
905  uint32 queueSlot = plr->GetBattlegroundQueueIndex(bg->GetTypeID());
906  if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
907  {
908  uint32 bgQueueTypeId = sBattlegroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
909  uint32 queueSlot = plr->GetBattlegroundQueueIndex(bgQueueTypeId);
910  if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
911  {
912  // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
913  BattlegroundQueue::QueuedPlayersMap const& qpMap = sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattlegroundQueueIdFromLevel()];
914  BattlegroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
915  if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
916  {
917  WorldPacket data;
918  sBattlegroundMgr.BuildBattlegroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME / 2, 0);
919  plr->GetSession()->SendPacket(&data);
920  }
921  }
922  }
923  return true; //event will be deleted
924 }
925 
927 {
928  //this should not be called
929  sLog.outError("Battleground invite event ABORTED!");
930 }
931 
932 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
933 {
934  Player* plr = sObjectMgr.GetPlayer(m_PlayerGuid);
935  if (!plr)
936  // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
937  return true;
938 
939  Battleground* bg = sBattlegroundMgr.GetBattleground(m_BgInstanceGUID);
940  if (!bg)
941  return true;
942 
943  sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.", plr->GetGUIDLow(), m_BgInstanceGUID);
944 
945  uint32 bgQueueTypeId = sBattlegroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
946  uint32 queueSlot = plr->GetBattlegroundQueueIndex(bgQueueTypeId);
947  if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
948  {
949  // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
950  BattlegroundQueue::QueuedPlayersMap::iterator qMapItr = sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattlegroundQueueIdFromLevel()].find(m_PlayerGuid);
951  if (qMapItr != sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattlegroundQueueIdFromLevel()].end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
952  {
953  plr->RemoveBattlegroundQueueId(bgQueueTypeId);
954  sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
955  sBattlegroundMgr.m_BattlegroundQueues[bgQueueTypeId].Update(bgQueueTypeId, bg->GetQueueType());
956  WorldPacket data;
957  sBattlegroundMgr.BuildBattlegroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0);
958  plr->GetSession()->SendPacket(&data);
959  }
960  }
961  else
962  sLog.outDebug("Battleground: Player was already removed from queue");
963 
964  //event will be deleted
965  return true;
966 }
967 
969 {
970  //this should not be called
971  sLog.outError("Battleground remove event ABORTED!");
972 }
973 
974 /*********************************************************/
975 /*** BATTLEGROUND MANAGER ***/
976 /*********************************************************/
977 
979 {
980  m_Battlegrounds.clear();
987  m_ArenaTesting = false;
988  m_Testing = false;
989 }
990 
992 {
994 }
995 
997 {
998  for (BattlegroundSet::iterator itr = m_Battlegrounds.begin(); itr != m_Battlegrounds.end();)
999  {
1000  Battleground* bg = itr->second;
1001  m_Battlegrounds.erase(itr++);
1002  delete bg;
1003  }
1004 
1005  // destroy template battlegrounds that listed only in queues (other already terminated)
1006  for (uint32 bgTypeId = 0; bgTypeId <= MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId)
1007  {
1008  // ~Battleground call unregistring BG from queue
1009  while (!BGFreeSlotQueue[bgTypeId].empty())
1010  delete BGFreeSlotQueue[bgTypeId].front();
1011  }
1012 }
1013 
1014 // used to update running battlegrounds, and delete finished ones
1016 {
1017  BattlegroundSet::iterator itr, next;
1018  for (itr = m_Battlegrounds.begin(); itr != m_Battlegrounds.end(); itr = next)
1019  {
1020  next = itr;
1021  ++next;
1022  itr->second->Update(diff);
1023  // use the SetDeleteThis variable
1024  // direct deletion caused crashes
1025  if (itr->second->m_SetDeleteThis)
1026  {
1027  Battleground* bg = itr->second;
1028  m_Battlegrounds.erase(itr);
1029  delete bg;
1030  }
1031  }
1032  // if rating difference counts, maybe force-update queues
1034  {
1035  // it's time to force update
1036  if (m_NextRatingDiscardUpdate < diff)
1037  {
1038  // forced update for level 70 rated arenas
1043  }
1044  else
1045  m_NextRatingDiscardUpdate -= diff;
1046  }
1048  {
1049  if (m_AutoDistributionTimeChecker < diff)
1050  {
1051  if (uint32(time(NULL)) > m_NextAutoDistributionTime)
1052  {
1055  CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '" UI64FMTD "'", m_NextAutoDistributionTime);
1056  }
1057  m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1058  }
1059  else
1061  }
1062 }
1063 
1064 void BattlegroundMgr::BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint32 /*team*/, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted)
1065 {
1066  // we can be in 3 queues in same time...
1067  if (StatusID == 0)
1068  {
1069  data->Initialize(SMSG_BATTLEFIELD_STATUS, 4 * 3);
1070  *data << uint32(QueueSlot); // queue id (0...2)
1071  *data << uint64(0);
1072  return;
1073  }
1074 
1075  data->Initialize(SMSG_BATTLEFIELD_STATUS, (4 + 1 + 1 + 4 + 2 + 4 + 1 + 4 + 4 + 4));
1076  *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1077  // The following segment is read as uint64 in client but can be appended as their original type.
1078  *data << uint8(arenatype ? arenatype : bg->GetArenaType());
1079  *data << uint8(bg->isArena() ? 0x0D : 0x2);
1080  *data << uint32(bg->GetTypeID());
1081  *data << uint16(0x1F90);
1082  // End of uint64 segment, decomposed this way for simplicity
1083  *data << uint32(0); // unknown
1084  // alliance/horde for BG and skirmish/rated for Arenas
1085  // following displays the minimap-icon 0 = faction icon 1 = arenaicon
1086  *data << uint8(israted ? israted : bg->isRated()); // 1 for rated match, 0 for bg or non rated match
1087  /* *data << uint8(arenatype ? arenatype : bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas // NOT PROPER VALUE IF ARENA ISN'T RUNNING YET!!!!
1088  switch(bg->GetTypeID()) // value depends on bg id
1089  {
1090  case BATTLEGROUND_AV:
1091  *data << uint8(1);
1092  break;
1093  case BATTLEGROUND_WS:
1094  *data << uint8(2);
1095  break;
1096  case BATTLEGROUND_AB:
1097  *data << uint8(3);
1098  break;
1099  case BATTLEGROUND_NA:
1100  *data << uint8(4);
1101  break;
1102  case BATTLEGROUND_BE:
1103  *data << uint8(5);
1104  break;
1105  case BATTLEGROUND_AA:
1106  *data << uint8(6);
1107  break;
1108  case BATTLEGROUND_EY:
1109  *data << uint8(7);
1110  break;
1111  case BATTLEGROUND_RL:
1112  *data << uint8(8);
1113  break;
1114  default: // unknown
1115  *data << uint8(0);
1116  break;
1117  }
1118 
1119  if (bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1120  *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1121  else
1122  *data << uint32(bg->GetTypeID()); // BG id from DBC
1123 
1124  *data << uint16(0x1F90); // unk value 8080
1125  *data << uint32(bg->GetInstanceID()); // instance id
1126 
1127  if (bg->isBattleground())
1128  *data << uint8(bg->GetTeamIndexByTeamId(team)); // team
1129  else
1130  *data << uint8(israted?israted:bg->isRated()); // is rated battle
1131  */
1132  *data << uint32(StatusID); // status
1133  switch (StatusID)
1134  {
1135  case STATUS_WAIT_QUEUE: // status_in_queue
1136  *data << uint32(Time1); // average wait time, milliseconds
1137  *data << uint32(Time2); // time in queue, updated every minute?
1138  break;
1139  case STATUS_WAIT_JOIN: // status_invite
1140  *data << uint32(bg->GetMapId()); // map id
1141  *data << uint32(Time1); // time to remove from queue, milliseconds
1142  break;
1143  case STATUS_IN_PROGRESS: // status_in_progress
1144  *data << uint32(bg->GetMapId()); // map id
1145  *data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds
1146  *data << uint32(Time2); // time from bg start, milliseconds
1147  *data << uint8(0x1); // Lua_GetBattlefieldArenaFaction (bool)
1148  break;
1149  default:
1150  sLog.outError("Unknown BG status!");
1151  break;
1152  }
1153 }
1154 
1156 {
1157  uint8 type = (bg->isArena() ? 1 : 0);
1158  // last check on 2.4.1
1159  data->Initialize(MSG_PVP_LOG_DATA, (1 + 1 + 4 + 40 * bg->GetPlayerScoresSize()));
1160  *data << uint8(type); // seems to be type (battleground=0/arena=1)
1161 
1162  if (type) // arena
1163  {
1164  // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1165  ArenaTeam* at1 = sObjectMgr.GetArenaTeamById(bg->m_ArenaTeamIds[1]); // Winner
1166  ArenaTeam* at2 = sObjectMgr.GetArenaTeamById(bg->m_ArenaTeamIds[0]); // Loser
1167 
1168  *data << uint32(at1 ? uint32(at1->GetRating()) : 0);
1169  *data << uint32(at1 ? uint32(at1->GetRating() + bg->m_ArenaTeamRatingChanges[1]) : 0);
1170  *data << uint32(at2 ? uint32(at2->GetRating()) : 0);
1171  *data << uint32(at2 ? uint32(at2->GetRating() + bg->m_ArenaTeamRatingChanges[0]) : 0);
1172 
1173  *data << (at1 ? at1->GetName() : "Unknown");
1174  *data << (at2 ? at2->GetName() : "Unknown");
1175  }
1176 
1177  if (bg->GetWinner() == 2)
1178  {
1179  *data << uint8(0); // bg in progress
1180  }
1181  else
1182  {
1183  *data << uint8(1); // bg ended
1184  *data << uint8(bg->GetWinner()); // who win
1185  }
1186 
1187  size_t wpos = data->wpos();
1188  uint32 scoreCount = 0;
1189  *data << uint32(scoreCount); // placeholder
1190 
1191  Battleground::BattlegroundScoreMap::const_iterator itr2 = bg->GetPlayerScoresBegin();
1192  for (Battleground::BattlegroundScoreMap::const_iterator itr = itr2; itr != bg->GetPlayerScoresEnd();)
1193  {
1194  itr2 = itr++;
1195  if (!bg->IsPlayerInBattleground(itr2->first))
1196  {
1197  sLog.outError("Player " UI64FMTD " has scoreboard entry for battleground %u but is not in battleground!", itr->first, bg->GetTypeID());
1198  continue;
1199  }
1200 
1201  *data << uint64(itr2->first);
1202  *data << uint32(itr2->second->KillingBlows);
1203  if (type == 0)
1204  {
1205  *data << uint32(itr2->second->HonorableKills);
1206  *data << uint32(itr2->second->Deaths);
1207  *data << uint32(itr2->second->BonusHonor);
1208  }
1209  else
1210  {
1211  Player* plr = sObjectMgr.GetPlayer(itr2->first);
1212  uint32 team = bg->GetPlayerTeam(itr2->first);
1213  if (!team && plr)
1214  team = plr->GetBGTeam();
1215  *data << uint8(team == ALLIANCE ? 1 : 0); // green or yellow
1216  }
1217  *data << uint32(itr2->second->DamageDone); // damage done
1218  *data << uint32(itr2->second->HealingDone); // healing done
1219  switch (bg->GetTypeID()) // battleground specific things
1220  {
1221  case BATTLEGROUND_AV:
1222  *data << uint32(0x00000005); // count of next fields
1223  *data << uint32(((BattlegroundAVScore*)itr2->second)->GraveyardsAssaulted); // GraveyardsAssaulted
1224  *data << uint32(((BattlegroundAVScore*)itr2->second)->GraveyardsDefended); // GraveyardsDefended
1225  *data << uint32(((BattlegroundAVScore*)itr2->second)->TowersAssaulted); // TowersAssaulted
1226  *data << uint32(((BattlegroundAVScore*)itr2->second)->TowersDefended); // TowersDefended
1227  *data << uint32(((BattlegroundAVScore*)itr2->second)->MinesCaptured); // MinesCaptured
1228  break;
1229  case BATTLEGROUND_WS:
1230  *data << uint32(0x00000002); // count of next fields
1231  *data << uint32(((BattlegroundWGScore*)itr2->second)->FlagCaptures); // flag captures
1232  *data << uint32(((BattlegroundWGScore*)itr2->second)->FlagReturns); // flag returns
1233  break;
1234  case BATTLEGROUND_AB:
1235  *data << uint32(0x00000002); // count of next fields
1236  *data << uint32(((BattlegroundABScore*)itr2->second)->BasesAssaulted); // bases asssulted
1237  *data << uint32(((BattlegroundABScore*)itr2->second)->BasesDefended); // bases defended
1238  break;
1239  case BATTLEGROUND_EY:
1240  *data << uint32(0x00000001); // count of next fields
1241  *data << uint32(((BattlegroundEYScore*)itr2->second)->FlagCaptures); // flag captures
1242  break;
1243  case BATTLEGROUND_NA:
1244  case BATTLEGROUND_BE:
1245  case BATTLEGROUND_AA:
1246  case BATTLEGROUND_RL:
1247  *data << uint32(0);
1248  break;
1249  default:
1250  sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1251  *data << uint32(0);
1252  break;
1253  }
1254  // should never happen
1255  if (++scoreCount >= bg->GetMaxPlayers() && itr != bg->GetPlayerScoresEnd())
1256  {
1257  sLog.outError("Battleground %u scoreboard has more entries (%u) than allowed players in this bg (%u)", bg->GetTypeID(), bg->GetPlayerScoresSize(), bg->GetMaxPlayers());
1258  break;
1259  }
1260  }
1261 
1262  data->put(wpos, scoreCount);
1263 }
1264 
1266 {
1267  /*bgTypeId is:
1268  0 - Your group has joined a battleground queue, but you are not eligible
1269  1 - Your group has joined the queue for AV
1270  2 - Your group has joined the queue for WS
1271  3 - Your group has joined the queue for AB
1272  4 - Your group has joined the queue for NA
1273  5 - Your group has joined the queue for BE Arena
1274  6 - Your group has joined the queue for All Arenas
1275  7 - Your group has joined the queue for EotS*/
1277  *data << uint32(bgTypeId);
1278 }
1279 
1281 {
1282  data->Initialize(SMSG_UPDATE_WORLD_STATE, 4 + 4);
1283  *data << uint32(field);
1284  *data << uint32(value);
1285 }
1286 
1288 {
1289  data->Initialize(SMSG_PLAY_SOUND, 4);
1290  *data << uint32(soundid);
1291 }
1292 
1294 {
1296  *data << uint64(guid);
1297 }
1298 
1300 {
1302  *data << uint64(plr->GetGUID());
1303 }
1304 
1305 void BattlegroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team)
1306 {
1307  // set invited player counters:
1308  Battleground* bg = GetBattleground(bgInstanceGUID);
1309  if (!bg)
1310  return;
1311  bg->IncreaseInvitedCount(team);
1312 
1313  plr->SetInviteForBattlegroundQueueType(BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()), bgInstanceGUID);
1314 
1315  // set the arena teams for rated matches
1316  if (bg->isArena() && bg->isRated())
1317  {
1318  switch (bg->GetArenaType())
1319  {
1320  case ARENA_TYPE_2v2:
1321  bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));
1322  break;
1323  case ARENA_TYPE_3v3:
1324  bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));
1325  break;
1326  case ARENA_TYPE_5v5:
1327  bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));
1328  break;
1329  default:
1330  break;
1331  }
1332  }
1333 
1334  // create invite events:
1335  //add events to player's counters ---- this is not good way - there should be something like global event processor, where we should add those events
1336  BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID);
1337  plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME / 2));
1338  BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team);
1340 }
1341 
1343 {
1344  return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();
1345 }
1346 
1347 // create a new battleground that will really be used to play
1349 {
1350  // get the template BG
1351  Battleground* bg_template = GetBattlegroundTemplate(bgTypeId);
1352 
1353  if (!bg_template)
1354  {
1355  sLog.outError("Battleground: CreateNewBattleground - bg template not found for %u", bgTypeId);
1356  return 0;
1357  }
1358 
1359  Battleground* bg = NULL;
1360 
1361  // create a copy of the BG template
1362  switch (bgTypeId)
1363  {
1364  case BATTLEGROUND_AV:
1365  bg = new BattlegroundAV(*(BattlegroundAV*)bg_template);
1366  break;
1367  case BATTLEGROUND_WS:
1368  bg = new BattlegroundWS(*(BattlegroundWS*)bg_template);
1369  break;
1370  case BATTLEGROUND_AB:
1371  bg = new BattlegroundAB(*(BattlegroundAB*)bg_template);
1372  break;
1373  case BATTLEGROUND_NA:
1374  bg = new BattlegroundNA(*(BattlegroundNA*)bg_template);
1375  break;
1376  case BATTLEGROUND_BE:
1377  bg = new BattlegroundBE(*(BattlegroundBE*)bg_template);
1378  break;
1379  case BATTLEGROUND_AA:
1380  bg = new BattlegroundAA(*(BattlegroundAA*)bg_template);
1381  break;
1382  case BATTLEGROUND_EY:
1383  bg = new BattlegroundEY(*(BattlegroundEY*)bg_template);
1384  break;
1385  case BATTLEGROUND_RL:
1386  bg = new BattlegroundRL(*(BattlegroundRL*)bg_template);
1387  break;
1388  default:
1389  //bg = new Battleground;
1390  return 0;
1391  break; // placeholder for non implemented BG
1392  }
1393 
1394  // generate a new instance id
1395  bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
1396 
1397  // reset the new bg (set status to status_wait_queue from status_none)
1398  bg->Reset();
1399 
1400  /* will be setup in BG::Update() when the first player is ported in
1401  if (!(bg->SetupBattleground()))
1402  {
1403  sLog.outError("Battleground: CreateNewBattleground: SetupBattleground failed for bg %u", bgTypeId);
1404  delete bg;
1405  return 0;
1406  }
1407  */
1408 
1409  // add BG to free slot queue
1410  bg->AddToBGFreeSlotQueue();
1411 
1413  bg->SetArenaType(arenaType);
1414  bg->SetRated(isRated);
1415  bg->SetTypeID(bgTypeId);
1416 
1417  // add bg to update list
1418  AddBattleground(bg->GetInstanceID(), bg);
1419 
1420  return bg;
1421 }
1422 
1423 // used to create the BG templates
1424 uint32 BattlegroundMgr::CreateBattleground(uint32 bgTypeId, 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, float StartMaxDist)
1425 {
1426  // Create the BG
1427  Battleground* bg = NULL;
1428 
1429  switch (bgTypeId)
1430  {
1431  case BATTLEGROUND_AV:
1432  bg = new BattlegroundAV;
1433  break;
1434  case BATTLEGROUND_WS:
1435  bg = new BattlegroundWS;
1436  break;
1437  case BATTLEGROUND_AB:
1438  bg = new BattlegroundAB;
1439  break;
1440  case BATTLEGROUND_NA:
1441  bg = new BattlegroundNA;
1442  break;
1443  case BATTLEGROUND_BE:
1444  bg = new BattlegroundBE;
1445  break;
1446  case BATTLEGROUND_AA:
1447  bg = new BattlegroundAA;
1448  break;
1449  case BATTLEGROUND_EY:
1450  bg = new BattlegroundEY;
1451  break;
1452  case BATTLEGROUND_RL:
1453  bg = new BattlegroundRL;
1454  break;
1455  default:
1456  bg = new Battleground;
1457  break; // placeholder for non implemented BG
1458  }
1459 
1460  bg->SetMapId(MapID);
1461 
1462  bg->Reset();
1463 
1464  BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
1465  //in previous method is checked if exists entry in sBattlemasterListStore, so no check needed
1466  if (bl)
1467  bg->SetArenaorBGType(bl->type == TYPE_ARENA);
1468 
1469  bg->SetTypeID(bgTypeId);
1470  bg->SetInstanceID(0); // template bg, instance id is 0
1471  bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1472  bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1473  bg->SetMinPlayers(MinPlayersPerTeam * 2);
1474  bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
1475  bg->SetName(BattlegroundName);
1476  bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1477  bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1478  bg->SetStartMaxDist(StartMaxDist);
1479  bg->SetLevelRange(LevelMin, LevelMax);
1480 
1481  //add Battleground instance to FreeSlotQueue (.back() will return the template!)
1482  bg->AddToBGFreeSlotQueue();
1483 
1484  // do NOT add to update list, since this is a template battleground!
1485 
1486  // return some not-null value, bgTypeId is good enough for me
1487  return bgTypeId;
1488 }
1489 
1491 {
1492  float AStartLoc[4];
1493  float HStartLoc[4];
1494  float StartMaxDist;
1495  uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1496  BattlemasterListEntry const* bl;
1497  WorldSafeLocsEntry const* start;
1498 
1499  uint32 count = 0;
1500 
1501  // 0 1 2 3 4 5 6 7 8 9
1502  QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO,StartMaxDist FROM battleground_template");
1503 
1504  if (!result)
1505  {
1506 
1507 
1508  sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table battleground_template is empty.");
1509  return;
1510  }
1511 
1512 
1513  do
1514  {
1515  Field* fields = result->Fetch();
1516 
1517  uint32 bgTypeID = fields[0].GetUInt32();
1518  if (sDisableMgr.IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeID, NULL))
1519  continue;
1520 
1521  // can be overwritten by values from DB
1522  bl = sBattlemasterListStore.LookupEntry(bgTypeID);
1523  if (!bl)
1524  {
1525  sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID);
1526  continue;
1527  }
1528 
1529  MaxPlayersPerTeam = bl->maxplayersperteam;
1530  MinPlayersPerTeam = bl->maxplayersperteam / 2;
1531  MinLvl = bl->minlvl;
1532  MaxLvl = bl->maxlvl;
1533 
1534  if (fields[1].GetUInt32())
1535  MinPlayersPerTeam = fields[1].GetUInt32();
1536 
1537  if (fields[2].GetUInt32())
1538  MaxPlayersPerTeam = fields[2].GetUInt32();
1539 
1540  if (fields[3].GetUInt32())
1541  MinLvl = fields[3].GetUInt32();
1542 
1543  if (fields[4].GetUInt32())
1544  MaxLvl = fields[4].GetUInt32();
1545 
1546  start1 = fields[5].GetUInt32();
1547 
1548  start = sWorldSafeLocsStore.LookupEntry(start1);
1549  if (start)
1550  {
1551  AStartLoc[0] = start->x;
1552  AStartLoc[1] = start->y;
1553  AStartLoc[2] = start->z;
1554  AStartLoc[3] = fields[6].GetFloat();
1555  }
1556  else if (bgTypeID == BATTLEGROUND_AA)
1557  {
1558  AStartLoc[0] = 0;
1559  AStartLoc[1] = 0;
1560  AStartLoc[2] = 0;
1561  AStartLoc[3] = fields[6].GetFloat();
1562  }
1563  else
1564  {
1565  sLog.outErrorDb("Table battleground_template for id %u has invalid WorldSafeLocs.dbc id %u in field AllianceStartLoc. BG not created.", bgTypeID, start1);
1566  continue;
1567  }
1568 
1569  start2 = fields[7].GetUInt32();
1570 
1571  start = sWorldSafeLocsStore.LookupEntry(start2);
1572  if (start)
1573  {
1574  HStartLoc[0] = start->x;
1575  HStartLoc[1] = start->y;
1576  HStartLoc[2] = start->z;
1577  HStartLoc[3] = fields[8].GetFloat();
1578  }
1579  else if (bgTypeID == BATTLEGROUND_AA)
1580  {
1581  HStartLoc[0] = 0;
1582  HStartLoc[1] = 0;
1583  HStartLoc[2] = 0;
1584  HStartLoc[3] = fields[8].GetFloat();
1585  }
1586  else
1587  {
1588  sLog.outErrorDb("Table battleground_template for id %u has invalid WorldSafeLocs.dbc id %u in field HordeStartLoc. BG not created.", bgTypeID, start2);
1589  continue;
1590  }
1591 
1592  StartMaxDist = fields[9].GetFloat();
1593 
1594  //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1595  if (!CreateBattleground(bgTypeID, 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], StartMaxDist))
1596  continue;
1597 
1598  ++count;
1599  }
1600  while (result->NextRow());
1601 
1602  sLog.outString(">> Loaded %u battlegrounds", count);
1603 }
1604 
1606 {
1608  {
1609  sLog.outDebug("Initializing Automatic Arena Point Distribution");
1610  QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1611  if (!result)
1612  {
1613  sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1615  CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('" UI64FMTD "')", m_NextAutoDistributionTime);
1616  }
1617  else
1618  m_NextAutoDistributionTime = (*result)[0].GetUInt64();
1619 
1620  sLog.outDebug("Automatic Arena Point Distribution initialized.");
1621  }
1622 }
1623 
1625 {
1626  // used to distribute arena points based on last week's stats
1627  sWorld.SendGlobalText("Flushing Arena points based on team ratings, this may take a few minutes. Please stand by...", NULL);
1628 
1629  sWorld.SendGlobalText("Distributing arena points to players...", NULL);
1630 
1631  //temporary structure for storing maximum points to add values for all players
1632  std::map<uint32, uint32> PlayerPoints;
1633 
1634  //at first update all points for all team members
1635  for (ObjectMgr::ArenaTeamMap::iterator team_itr = sObjectMgr.GetArenaTeamMapBegin(); team_itr != sObjectMgr.GetArenaTeamMapEnd(); ++team_itr)
1636  {
1637  if (ArenaTeam* at = team_itr->second)
1638  at->UpdateArenaPointsHelper(PlayerPoints);
1639  }
1640 
1641  //cycle that gives points to all players
1642  for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1643  {
1644  //add points if player is online
1645  if (Player* player = HashMapHolder<Player>::Find(plr_itr->first))
1646  player->ModifyArenaPoints(plr_itr->second, true);
1647  else
1648  CharacterDatabase.PExecute("UPDATE characters SET arenaPoints = arenaPoints + '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
1649  }
1650 
1651  PlayerPoints.clear();
1652 
1653  sWorld.SendGlobalText("Finished setting arena points for online players.", NULL);
1654 
1655  sWorld.SendGlobalText("Modifying played count, arena points etc. for loaded arena teams, sending updated stats to online players...", NULL);
1656  for (ObjectMgr::ArenaTeamMap::iterator titr = sObjectMgr.GetArenaTeamMapBegin(); titr != sObjectMgr.GetArenaTeamMapEnd(); ++titr)
1657  {
1658  if (ArenaTeam* at = titr->second)
1659  {
1660  at->FinishWeek(); // set played this week etc values to 0 in memory, too
1661  at->SaveToDB(); // save changes
1662  at->NotifyStatsChanged(); // notify the players of the changes
1663  }
1664  }
1665 
1666  sWorld.SendGlobalText("Modification done.", NULL);
1667 
1668  sWorld.SendGlobalText("Done flushing Arena points.", NULL);
1669 }
1670 
1672 {
1673  uint32 PlayerLevel = 10;
1674 
1675  if (plr)
1676  PlayerLevel = plr->getLevel();
1677 
1679  *data << uint64(guid); // battlemaster guid
1680  *data << uint32(bgTypeId); // battleground id
1681  if (bgTypeId == BATTLEGROUND_AA) // arena
1682  {
1683  *data << uint8(5); // unk
1684  *data << uint32(0); // unk
1685  }
1686  else // battleground
1687  {
1688  *data << uint8(0x00); // unk
1689 
1690  size_t count_pos = data->wpos();
1691  uint32 count = 0;
1692  *data << uint32(0x00); // number of bg instances
1693 
1694  for (std::map<uint32, Battleground*>::iterator itr = m_Battlegrounds.begin(); itr != m_Battlegrounds.end(); ++itr)
1695  {
1696  if (itr->second->GetTypeID() == bgTypeId && (PlayerLevel >= itr->second->GetMinLevel()) && (PlayerLevel <= itr->second->GetMaxLevel()))
1697  {
1698  *data << uint32(itr->second->GetInstanceID());
1699  ++count;
1700  }
1701  }
1702  data->put<uint32>(count_pos , count);
1703  }
1704 }
1705 
1707 {
1708  Battleground* bg = GetBattleground(instanceId);
1709  if (bg)
1710  {
1711  uint32 mapid = bg->GetMapId();
1712  float x, y, z, O;
1713  uint32 team = pl->GetBGTeam();
1714  if (team == 0)
1715  team = pl->GetTeam();
1716  bg->GetTeamStartLoc(team, x, y, z, O);
1717 
1718  sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1719  pl->TeleportTo(mapid, x, y, z, O);
1720  }
1721  else
1722  sLog.outError("player %u trying to port to non-existent bg instance %u", pl->GetGUIDLow(), instanceId);
1723 }
1724 
1726 {
1728  uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
1729  if (time_ == uint32(-1))
1730  time_ = 0;
1731  data << guid << time_;
1732  pl->GetSession()->SendPacket(&data);
1733 }
1734 
1736 {
1737  BattlegroundSet::iterator itr = m_Battlegrounds.find(instanceID);
1738  if (itr != m_Battlegrounds.end())
1739  m_Battlegrounds.erase(itr);
1740 }
1741 
1743 {
1744  return (bgTypeId == BATTLEGROUND_AA ||
1745  bgTypeId == BATTLEGROUND_BE ||
1746  bgTypeId == BATTLEGROUND_NA ||
1747  bgTypeId == BATTLEGROUND_RL);
1748 }
1749 
1751 {
1752  return !IsArenaType(bgTypeId);
1753 }
1754 
1756 {
1757  switch (bgTypeId)
1758  {
1759  case BATTLEGROUND_WS:
1760  return BATTLEGROUND_QUEUE_WS;
1761  case BATTLEGROUND_AB:
1762  return BATTLEGROUND_QUEUE_AB;
1763  case BATTLEGROUND_AV:
1764  return BATTLEGROUND_QUEUE_AV;
1765  case BATTLEGROUND_EY:
1766  return BATTLEGROUND_QUEUE_EY;
1767  case BATTLEGROUND_AA:
1768  case BATTLEGROUND_NA:
1769  case BATTLEGROUND_RL:
1770  case BATTLEGROUND_BE:
1771  switch (arenaType)
1772  {
1773  case ARENA_TYPE_2v2:
1774  return BATTLEGROUND_QUEUE_2v2;
1775  case ARENA_TYPE_3v3:
1776  return BATTLEGROUND_QUEUE_3v3;
1777  case ARENA_TYPE_5v5:
1778  return BATTLEGROUND_QUEUE_5v5;
1779  default:
1780  return 0;
1781  }
1782  default:
1783  return 0;
1784  }
1785 }
1786 
1788 {
1789  switch (bgQueueTypeId)
1790  {
1791  case BATTLEGROUND_QUEUE_WS:
1792  return BATTLEGROUND_WS;
1793  case BATTLEGROUND_QUEUE_AB:
1794  return BATTLEGROUND_AB;
1795  case BATTLEGROUND_QUEUE_AV:
1796  return BATTLEGROUND_AV;
1797  case BATTLEGROUND_QUEUE_EY:
1798  return BATTLEGROUND_EY;
1802  return BATTLEGROUND_AA;
1803  default:
1804  return 0;
1805  }
1806 }
1807 
1809 {
1810  switch (bgQueueTypeId)
1811  {
1813  return ARENA_TYPE_2v2;
1815  return ARENA_TYPE_3v3;
1817  return ARENA_TYPE_5v5;
1818  default:
1819  return 0;
1820  }
1821 }
1822 
1824 {
1825  m_Testing = !m_Testing;
1826  if (m_Testing)
1827  sWorld.SendGlobalText("Battlegrounds are set to 1v0 for debugging.", NULL);
1828  else
1829  sWorld.SendGlobalText("Battlegrounds are set to normal playercount.", NULL);
1830 }
1831 
1833 {
1835  if (m_ArenaTesting)
1836  sWorld.SendGlobalText("Arenas are set to 1v1 for debugging. So, don't join as group.", NULL);
1837  else
1838  sWorld.SendGlobalText("Arenas are set to normal playercount.", NULL);
1839 }
1840 
1842 {
1843  for (uint32 bgtype = 1; bgtype <= 8; ++bgtype)
1844  {
1845  if (Battleground* bg = GetBattlegroundTemplate(bgtype))
1846  bg->SetHoliday(mask & (1 << bgtype));
1847  }
1848 }
1849 
void OfflineMemberLost(uint64 guid, uint32 againstRating)
Definition: ArenaTeam.cpp:627
DBCStorage< WorldSafeLocsEntry > sWorldSafeLocsStore(WorldSafeLocsEntryfmt)
uint32 GetMinPlayersPerTeam() const
Definition: Battleground.h:355
EventProcessor m_Events
Definition: Unit.h:1746
ArenaType
Definition: Battleground.h:189
uint32 GetPlayersSize() const
Definition: Battleground.h:499
Battleground * GetBattleground(uint32 InstanceID)
SelectionPool m_SelectionPools[NUM_SELECTION_POOL_TYPES]
BattlegroundQueue m_BattlegroundQueues[MAX_BATTLEGROUND_QUEUE_TYPES]
uint32 GetFreeSlotsForTeam(uint32 Team) const
void SetMinPlayersPerTeam(uint32 MinPlayers)
Definition: Battleground.h:450
#define GUID_LOPART(x)
Definition: ObjectGuid.h:110
uint32 ArenaTeamRating
uint32 CreateBattleground(uint32 bgTypeId, 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, float StartMaxDist)
void SetMaxPlayersPerTeam(uint32 MaxPlayers)
Definition: Battleground.h:446
void Init(QueuedGroupsList *source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType=0, bool IsRated=false, uint32 MinRating=0, uint32 MaxRating=0, uint32 DisregardTime=0, uint32 excludeTeam=0)
#define sDisableMgr
Definition: DisableMgr.h:73
void DecreaseInvitedCount(uint32 team)
Definition: Battleground.h:462
virtual bool Execute(uint64 e_time, uint32 p_time)
DatabaseType WorldDatabase
Accessor to the world database.
Definition: Main.cpp:53
uint8 GetWinner() const
Definition: Battleground.h:368
virtual void Abort(uint64 e_time)
void SetQueueType(uint32 ID)
Definition: Battleground.h:383
#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY
QueuedPlayersMap m_QueuedPlayers[MAX_BATTLEGROUND_QUEUES]
#define MAX_BATTLEGROUND_QUEUES
void AddEvent(BasicEvent *Event, uint64 e_time, bool set_addtime=true)
void MemberLost(Player *plr, uint32 againstRating)
Definition: ArenaTeam.cpp:605
std::map< uint64, PlayerQueueInfo > QueuedPlayersMap
GroupQueueInfo * GroupInfo
Definition: Field.h:24
#define PLAYER_MAX_BATTLEGROUND_QUEUES
void SetDeleteThis()
Definition: Battleground.h:698
void RemoveBattleground(uint32 instanceID)
Battleground * GetBattlegroundTemplate(uint32 bgTypeId)
DBCStorage< BattlemasterListEntry > sBattlemasterListStore(BattlemasterListEntryfmt)
void SetArenaType(uint8 type)
Definition: Battleground.h:424
void InitAutomaticArenaPointDistribution()
uint32 getMSTime()
Definition: Timer.h:32
int32 m_ArenaTeamRatingChanges[BG_TEAMS_COUNT]
Definition: Battleground.h:777
#define sLog
Log class singleton.
Definition: Log.h:187
ACE_INT32 int32
Definition: Define.h:67
uint32 m_RatingDiscardTimer
void Init(EligibleGroups *curr)
bool IsPlayerInBattleground(uint64 guid)
void Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype=0, bool isRated=false, uint32 minRating=0)
QueryResult_AutoPtr Query(const char *sql)
Definition: Database.cpp:383
bool IsArenaType(uint32 bgTypeId) const
uint32 GetBGTeam() const
Definition: Player.h:2316
uint8 BGArenaType(uint32 bgQueueTypeId) const
void BuildPlayerLeftBattlegroundPacket(WorldPacket *data, const uint64 &guid)
void Initialize(uint16 opcode, size_t newres=200)
Definition: WorldPacket.h:37
uint32 GetPlayerTeam(uint64 guid)
uint32 GetPlayerScoresSize() const
Definition: Battleground.h:517
uint32 GetGUIDLow() const
Definition: Object.h:160
uint64 CalculateTime(uint64 t_offset)
uint32 m_MaxRatingDifference
QueuedGroupsList m_QueuedGroups[MAX_BATTLEGROUND_QUEUES]
void SetInstanceID(uint32 InstanceID)
Definition: Battleground.h:387
GroupQueueInfo * AddGroup(Player *leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 ArenaRating, uint32 ArenaTeamId=0)
#define sObjectMgr
Definition: ObjectMgr.h:1285
void SendPacket(WorldPacket const *packet)
INSTANTIATE_SINGLETON_1(BattlegroundMgr)
static uint32 GetMinLevelForBattlegroundQueueId(uint32 queue_id)
Definition: Player.cpp:19416
void SetInviteForBattlegroundQueueType(uint32 bgQueueType, uint32 instanceId)
Definition: Player.h:2289
void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, uint32 bgTypeId)
void SetStartMaxDist(float startMaxDist)
Definition: Battleground.h:459
void RemoveGroup(GroupQueueInfo *group)
std::list< GroupQueueInfo * > QueuedGroupsList
virtual bool Execute(uint64 e_time, uint32 p_time)
bool isRated() const
Definition: Battleground.h:489
uint32 GetInvitedCount(uint32 team) const
Definition: Battleground.h:470
uint32 GetRating() const
Definition: ArenaTeam.h:150
bool isArena() const
Definition: Battleground.h:481
BattlegroundScoreMap::const_iterator GetPlayerScoresBegin() const
Definition: Battleground.h:509
size_t wpos() const
Definition: ByteBuffer.h:264
void BuildPvpLogDataPacket(WorldPacket *data, Battleground *bg)
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options=0)
Definition: Player.cpp:1556
std::list< GroupQueueInfo * > SelectedGroups
ACE_UINT8 uint8
Definition: Define.h:73
virtual void Abort(uint64 e_time)
#define UI64FMTD
Definition: Common.h:149
uint8 GetArenaType() const
Definition: Battleground.h:364
void InvitePlayer(Player *plr, uint32 bgInstanceGUID, uint32 team)
uint32 GetQueueType() const
Definition: Battleground.h:309
void AddPlayer(Player *plr, GroupQueueInfo *ginfo)
bool Build(uint32 MinPlayers, uint32 MaxPlayers, EligibleGroups::iterator startitr)
void SetLevelRange(uint32 min, uint32 max)
Definition: Battleground.h:415
uint32 GetBattlegroundQueueIndex(uint32 bgQueueType) const
Definition: Player.h:2234
void PSendSysMessage(const char *format,...) ATTR_PRINTF(2
Definition: Chat.cpp:855
uint32 m_PrematureFinishTimer
void AddBattleground(uint32 ID, Battleground *BG)
EligibleGroups m_EligibleGroups
void put(size_t pos, T value)
Definition: ByteBuffer.h:79
bool IsBattlegroundType(uint32 bgTypeId) const
void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
etc mysql my cnf *Then change max_allowed_packet to a bigger value
void SetArenaorBGType(bool _isArena)
Definition: Battleground.h:428
void SetMapId(uint32 MapID)
Definition: Battleground.h:535
std::map< uint64, PlayerQueueInfo * > Players
void BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
void SendAreaSpiritHealerQueryOpcode(Player *pl, Battleground *bg, uint64 guid)
static uint32 BGQueueTypeId(uint32 bgTypeId, uint8 arenaType)
void RemoveFromBGFreeSlotQueue()
BattlegroundScoreMap::const_iterator GetPlayerScoresEnd() const
Definition: Battleground.h:513
bool PExecute(const char *format,...) ATTR_PRINTF(2
Definition: Database.cpp:441
BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPES]
void SetRated(bool state)
Definition: Battleground.h:420
void AddToBGFreeSlotQueue()
uint32 GetInstanceID() const
Definition: Battleground.h:313
void SetName(char const *Name)
Definition: Battleground.h:375
uint32 OpponentsTeamRating
void SaveToDB()
Definition: ArenaTeam.cpp:702
void CreateInitialBattlegrounds()
const char * GetName() const
Definition: Object.h:692
void RemovePlayer(uint64 guid, bool decreaseInvitedCount)
ACE_UINT64 uint64
Definition: Define.h:70
std::string GetName() const
Definition: ArenaTeam.h:141
uint32 BGTemplateId(uint32 bgQueueTypeId) const
void IncreaseInvitedCount(uint32 team)
Definition: Battleground.h:466
uint32 m_NextRatingDiscardUpdate
uint32 GetArenaTeamId(uint8 slot)
Definition: Player.h:1862
uint32 GetTypeID() const
Definition: Battleground.h:305
void Update(uint32 diff)
void BuildBattlegroundStatusPacket(WorldPacket *data, Battleground *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype=0, uint8 israted=0)
static uint32 GetMaxLevelForBattlegroundQueueId(uint32 queue_id)
Definition: Player.cpp:19427
#define MAX_BATTLEGROUND_TYPE_ID
Definition: Battleground.h:149
ACE_Refcounted_Auto_Ptr< QueryResult, ACE_Null_Mutex > QueryResult_AutoPtr
Definition: QueryResult.h:113
uint32 GetMaxPlayersPerTeam() const
Definition: Battleground.h:351
void GetTeamStartLoc(uint32 TeamID, float &X, float &Y, float &Z, float &O) const
Definition: Battleground.h:556
void BuildBattlegroundListPacket(WorldPacket *data, uint64 guid, Player *plr, uint32 bgTypeId)
bool HasFreeSlots() const
#define sBattlegroundMgr
uint32 GetTeam() const
Definition: Player.h:2075
void SetArenaTeamIdForTeam(uint32 Team, uint32 ArenaTeamId)
Definition: Battleground.h:627
void SetStatus(uint32 Status)
Definition: Battleground.h:391
char const * GetName() const
Definition: Battleground.h:301
Battleground * CreateNewBattleground(uint32 bgTypeId, uint8 arenaType, bool isRated)
uint32 GetMapId() const
Definition: Battleground.h:539
bool InviteGroupToBG(GroupQueueInfo *ginfo, Battleground *bg, uint32 side)
void StartBattleground()
uint32 GetLastResurrectTime() const
Definition: Battleground.h:329
WorldSession * GetSession() const
Definition: Player.h:1959
#define sWorld
Definition: World.h:860
DatabaseType CharacterDatabase
Accessor to the character database.
Definition: Main.cpp:54
ACE_UINT16 uint16
Definition: Define.h:72
void BuildPlayerJoinedBattlegroundPacket(WorldPacket *data, Player *plr)
void SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
uint32 GetMaxPlayers() const
Definition: Battleground.h:333
void SendToBattleground(Player *pl, uint32 bgTypeId)
ACE_UINT32 uint32
Definition: Define.h:71
void SetHolidayWeekends(uint32 mask)
uint32 GetBattlegroundQueueIdFromLevel() const
Definition: Player.cpp:19436
uint64 m_NextAutoDistributionTime
uint32 m_ArenaTeamIds[BG_TEAMS_COUNT]
Definition: Battleground.h:775
void DeleteAlllBattlegrounds()
BattlegroundSet m_Battlegrounds
uint32 getLevel() const
Definition: Unit.h:1029
void AddGroup(GroupQueueInfo *group)
void SetMaxPlayers(uint32 MaxPlayers)
Definition: Battleground.h:407
void RemoveBattlegroundQueueId(uint32 val)
Definition: Player.h:2277
Definition: Player.h:922
bool BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType=0, bool isRated=false, uint32 MinRating=0, uint32 MaxRating=0, uint32 DisregardTime=0, uint32 excludeTeam=0)
uint32 m_AutoDistributionTimeChecker
uint32 IsInvitedToBGInstanceGUID
void SetTypeID(uint32 TypeID)
Definition: Battleground.h:379
void SetMinPlayers(uint32 MinPlayers)
Definition: Battleground.h:411
uint32 urand(uint32 min, uint32 max)
Definition: Util.cpp:71
const uint64 & GetGUID() const
Definition: Object.h:156
void BGEndedRemoveInvites(Battleground *bg)