[7026] Current arena season id and state send and setting in mangosd.conf.
[getmangos.git] / src / game / BattleGroundMgr.cpp
blobfe97ecca3326d6cfd5a59072c629464b12852cef
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Player.h"
21 #include "BattleGroundMgr.h"
22 #include "BattleGroundAV.h"
23 #include "BattleGroundAB.h"
24 #include "BattleGroundEY.h"
25 #include "BattleGroundWS.h"
26 #include "BattleGroundNA.h"
27 #include "BattleGroundBE.h"
28 #include "BattleGroundAA.h"
29 #include "BattleGroundRL.h"
30 #include "BattleGroundSA.h"
31 #include "BattleGroundDS.h"
32 #include "BattleGroundRV.h"
33 #include "SharedDefines.h"
34 #include "Policies/SingletonImp.h"
35 #include "MapManager.h"
36 #include "Map.h"
37 #include "MapInstanced.h"
38 #include "ObjectMgr.h"
39 #include "ProgressBar.h"
40 #include "World.h"
41 #include "Chat.h"
42 #include "ArenaTeam.h"
44 INSTANTIATE_SINGLETON_1( BattleGroundMgr );
46 /*********************************************************/
47 /*** BATTLEGROUND QUEUE SYSTEM ***/
48 /*********************************************************/
50 BattleGroundQueue::BattleGroundQueue()
52 //queues are empty, we don't have to call clear()
53 /* for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
55 //m_QueuedPlayers[i].Horde = 0;
56 //m_QueuedPlayers[i].Alliance = 0;
57 //m_QueuedPlayers[i].AverageTime = 0;
58 }*/
61 BattleGroundQueue::~BattleGroundQueue()
63 for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
65 m_QueuedPlayers[i].clear();
66 for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr)
68 delete (*itr);
70 m_QueuedGroups[i].clear();
74 // initialize eligible groups from the given source matching the given specifications
75 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)
77 // clear from prev initialization
78 clear();
79 BattleGroundQueue::QueuedGroupsList::iterator itr, next;
80 // iterate through the source
81 for(itr = source->begin(); itr!= source->end(); itr = next)
83 next = itr;
84 ++next;
85 if( (*itr)->BgTypeId == BgTypeId && // bg type must match
86 (*itr)->ArenaType == ArenaType && // arena type must match
87 (*itr)->IsRated == IsRated && // israted must match
88 (*itr)->IsInvitedToBGInstanceGUID == 0 && // leave out already invited groups
89 (*itr)->Team == side && // match side
90 (*itr)->Players.size() <= MaxPlayers && // the group must fit in the bg
91 ( !excludeTeam || (*itr)->ArenaTeamId != excludeTeam ) && // if excludeTeam is specified, leave out those arena team ids
92 ( !IsRated || (*itr)->Players.size() == MaxPlayers ) && // if rated, then pass only if the player count is exact NEEDS TESTING! (but now this should never happen)
93 ( (*itr)->JoinTime <= DisregardTime // pass if disregard time is greater than join time
94 || (*itr)->ArenaTeamRating == 0 // pass if no rating info
95 || ( (*itr)->ArenaTeamRating >= MinRating // pass if matches the rating range
96 && (*itr)->ArenaTeamRating <= MaxRating ) ) )
98 // the group matches the conditions
99 // insert it in order of groupsize, and join time
100 uint32 size = (*itr)->Players.size();
101 uint32 jointime = (*itr)->JoinTime;
102 bool inserted = false;
104 for(std::list<GroupQueueInfo *>::iterator elig_itr = begin(); elig_itr != end(); ++elig_itr)
106 // if the next one's size is smaller, then insert
107 // also insert if the next one's size is equal, but it joined the queue later
108 if( ((*elig_itr)->Players.size()<size) ||
109 ((*elig_itr)->Players.size() == size && (*elig_itr)->JoinTime > jointime) )
111 insert(elig_itr,(*itr));
112 inserted = true;
113 break;
116 // if not inserted -> this is the smallest group -> push_back
117 if(!inserted)
119 push_back((*itr));
125 // remove group from eligible groups
126 // used when building selection pools
127 void BattleGroundQueue::EligibleGroups::RemoveGroup(GroupQueueInfo * ginfo)
129 for(std::list<GroupQueueInfo *>::iterator itr = begin(); itr != end(); ++itr)
131 if((*itr)==ginfo)
133 erase(itr);
134 return;
139 // selection pool initialization, used to clean up from prev selection
140 void BattleGroundQueue::SelectionPool::Init()
142 SelectedGroups.clear();
143 MaxGroup = 0;
144 PlayerCount = 0;
147 // get the maximal group from the selection pool
148 // used when building the pool, and have to remove the largest
149 GroupQueueInfo * BattleGroundQueue::SelectionPool::GetMaximalGroup()
151 if(SelectedGroups.empty())
153 sLog.outError("Getting max group when selection pool is empty, this should never happen.");
154 MaxGroup = NULL;
155 return 0;
157 // actually select the max group if it's not set
158 if(MaxGroup==0 && !SelectedGroups.empty())
160 uint32 max_size = 0;
161 for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
163 if(max_size<(*itr)->Players.size())
165 MaxGroup =(*itr);
166 max_size = MaxGroup->Players.size();
170 return MaxGroup;
173 // remove group info from selection pool
174 // used when building selection pools and have to remove maximal group
175 void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)
177 // uninitiate max group info if needed
178 if(MaxGroup == ginfo)
179 MaxGroup = 0;
180 // find what to remove
181 for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
183 if((*itr)==ginfo)
185 SelectedGroups.erase(itr);
186 // decrease selected players count
187 PlayerCount -= ginfo->Players.size();
188 return;
193 // add group to selection
194 // used when building selection pools
195 void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)
197 SelectedGroups.push_back(ginfo);
198 // increase selected players count
199 PlayerCount+=ginfo->Players.size();
200 if(!MaxGroup || ginfo->Players.size() > MaxGroup->Players.size())
202 // update max group info if needed
203 MaxGroup = ginfo;
207 // add group to bg queue with the given leader and bg specifications
208 GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating, uint32 arenateamid)
210 uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel();
212 // create new ginfo
213 // cannot use the method like in addplayer, because that could modify an in-queue group's stats
214 // (e.g. leader leaving queue then joining as individual again)
215 GroupQueueInfo* ginfo = new GroupQueueInfo;
216 ginfo->BgTypeId = BgTypeId;
217 ginfo->ArenaType = ArenaType;
218 ginfo->ArenaTeamId = arenateamid;
219 ginfo->IsRated = isRated;
220 ginfo->IsInvitedToBGInstanceGUID = 0; // maybe this should be modifiable by function arguments to enable selection of running instances?
221 ginfo->JoinTime = getMSTime();
222 ginfo->Team = leader->GetTeam();
223 ginfo->ArenaTeamRating = arenaRating;
224 ginfo->OpponentsTeamRating = 0; //initialize it to 0
226 ginfo->Players.clear();
228 m_QueuedGroups[queue_id].push_back(ginfo);
230 // return ginfo, because it is needed to add players to this group info
231 return ginfo;
234 void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
236 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
238 //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
239 PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()];
240 info.InviteTime = 0;
241 info.LastInviteTime = 0;
242 info.LastOnlineTime = getMSTime();
243 info.GroupInfo = ginfo;
245 // add the pinfo to ginfo's list
246 ginfo->Players[plr->GetGUID()] = &info;
249 void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
251 Player *plr = objmgr.GetPlayer(guid);
253 uint32 queue_id = 0;
254 QueuedPlayersMap::iterator itr;
255 GroupQueueInfo * group;
256 QueuedGroupsList::iterator group_itr;
257 bool IsSet = false;
258 if(plr)
260 queue_id = plr->GetBattleGroundQueueIdFromLevel();
262 itr = m_QueuedPlayers[queue_id].find(guid);
263 if(itr != m_QueuedPlayers[queue_id].end())
264 IsSet = true;
267 if(!IsSet)
269 // either player is offline, or he levelled up to another queue category
270 // sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");
271 for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
273 itr = m_QueuedPlayers[i].find(guid);
274 if(itr != m_QueuedPlayers[i].end())
276 queue_id = i;
277 IsSet = true;
278 break;
283 // couldn't find the player in bg queue, return
284 if(!IsSet)
286 sLog.outError("Battleground: couldn't find player to remove.");
287 return;
290 group = itr->second.GroupInfo;
292 for(group_itr=m_QueuedGroups[queue_id].begin(); group_itr != m_QueuedGroups[queue_id].end(); ++group_itr)
294 if(group == (GroupQueueInfo*)(*group_itr))
295 break;
298 // variables are set (what about leveling up when in queue????)
299 // remove player from group
300 // if only player there, remove group
302 // remove player queue info from group queue info
303 std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
305 if(pitr != group->Players.end())
306 group->Players.erase(pitr);
308 // check for iterator correctness
309 if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())
311 // used when player left the queue, NOT used when porting to bg
312 if (decreaseInvitedCount)
314 // if invited to bg, and should decrease invited count, then do it
315 if(group->IsInvitedToBGInstanceGUID)
317 BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID);
318 if (bg)
319 bg->DecreaseInvitedCount(group->Team);
320 if (bg && !bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE))
322 // no more players on battleground, set delete it
323 bg->SetDeleteThis();
326 // update the join queue, maybe now the player's group fits in a queue!
327 // not yet implemented (should store bgTypeId in group queue info?)
329 // remove player queue info
330 m_QueuedPlayers[queue_id].erase(itr);
331 // remove group queue info if needed
333 //if we left BG queue(not porting) OR if arena team left queue for rated match
334 if((decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()))
335 AnnounceWorld(group, guid, false);
337 if(group->Players.empty())
339 m_QueuedGroups[queue_id].erase(group_itr);
340 delete group;
342 // NEEDS TESTING!
343 // group wasn't empty, so it wasn't deleted, and player have left a rated queue -> everyone from the group should leave too
344 // don't remove recursively if already invited to bg!
345 else if(!group->IsInvitedToBGInstanceGUID && decreaseInvitedCount && group->IsRated)
347 // remove next player, this is recursive
348 // first send removal information
349 if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
351 BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
352 uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(group->BgTypeId,group->ArenaType);
353 uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
354 plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
355 WorldPacket data;
356 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr2->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
357 plr2->GetSession()->SendPacket(&data);
359 // then actually delete, this may delete the group as well!
360 RemovePlayer(group->Players.begin()->first,decreaseInvitedCount);
365 void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, uint64 playerGUID, bool isAddedToQueue)
368 if(ginfo->ArenaType) //if Arena
370 if( sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated)
372 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
373 if(!bg)
374 return;
376 char const* bgName = bg->GetName();
377 if(isAddedToQueue)
378 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
379 else
380 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
383 else //if BG
385 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
387 Player *plr = objmgr.GetPlayer(playerGUID);
388 if(!plr)
389 return;
391 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
392 if(!bg)
393 return;
395 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
396 char const* bgName = bg->GetName();
398 uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id);
399 uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id);
401 // replace hardcoded max level by player max level for nice output
402 if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
403 q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
405 int8 MinPlayers = bg->GetMinPlayersPerTeam();
407 uint8 qHorde = 0;
408 uint8 qAlliance = 0;
410 uint32 bgTypeId = ginfo->BgTypeId;
411 QueuedPlayersMap::iterator itr;
412 for(itr = m_QueuedPlayers[queue_id].begin(); itr!= m_QueuedPlayers[queue_id].end(); ++itr)
414 if(itr->second.GroupInfo->BgTypeId == bgTypeId)
416 switch(itr->second.GroupInfo->Team)
418 case HORDE:
419 qHorde++; break;
420 case ALLIANCE:
421 qAlliance++; break;
422 default:
423 break;
428 // Show queue status to player only (when joining queue)
429 if(sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
431 ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
432 bgName, q_min_level, q_max_level, qAlliance, MinPlayers, qHorde, MinPlayers);
434 // System message
435 else
437 sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
438 bgName, q_min_level, q_max_level, qAlliance, MinPlayers, qHorde, MinPlayers);
444 bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
446 // set side if needed
447 if(side)
448 ginfo->Team = side;
450 if(!ginfo->IsInvitedToBGInstanceGUID)
452 // not yet invited
453 // set invitation
454 ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
455 uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
456 // loop through the players
457 for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
459 // set status
460 itr->second->InviteTime = getMSTime();
461 itr->second->LastInviteTime = getMSTime();
463 // get the player
464 Player* plr = objmgr.GetPlayer(itr->first);
465 // if offline, skip him
466 if(!plr)
467 continue;
469 // invite the player
470 sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team);
472 WorldPacket data;
474 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
476 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());
478 // send status packet
479 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, side?side:plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
480 plr->GetSession()->SendPacket(&data);
482 return true;
485 return false;
488 // this function is responsible for the selection of queued groups when trying to create new battlegrounds
489 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)
491 uint32 side;
492 switch(mode)
494 case NORMAL_ALLIANCE:
495 case ONESIDE_ALLIANCE_TEAM1:
496 case ONESIDE_ALLIANCE_TEAM2:
497 side = ALLIANCE;
498 break;
499 case NORMAL_HORDE:
500 case ONESIDE_HORDE_TEAM1:
501 case ONESIDE_HORDE_TEAM2:
502 side = HORDE;
503 break;
504 default:
505 //unknown mode, return false
506 sLog.outDebug("Battleground: unknown selection pool build mode, returning...");
507 return false;
508 break;
511 // inititate the groups eligible to create the bg
512 m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime, excludeTeam);
513 // init the selected groups (clear)
514 m_SelectionPools[mode].Init();
515 while(!(m_EligibleGroups.empty()))
517 sLog.outDebug("m_EligibleGroups is not empty, continue building selection pool");
518 // in decreasing group size, add groups to join if they fit in the MaxPlayersPerTeam players
519 for(EligibleGroups::iterator itr= m_EligibleGroups.begin(); itr!=m_EligibleGroups.end(); ++itr)
521 // get the maximal not yet checked group
522 GroupQueueInfo * MaxGroup = (*itr);
523 // if it fits in the maxplayer size, add it
524 if( (m_SelectionPools[mode].GetPlayerCount() + MaxGroup->Players.size()) <= MaxPlayers )
526 m_SelectionPools[mode].AddGroup(MaxGroup);
529 if(m_SelectionPools[mode].GetPlayerCount()>=MinPlayers)
531 // the selection pool is set, return
532 sLog.outDebug("pool build succeeded, return true");
533 return true;
535 // if the selection pool's not set, then remove the group with the highest player count, and try again with the rest.
536 GroupQueueInfo * MaxGroup = m_SelectionPools[mode].GetMaximalGroup();
537 m_EligibleGroups.RemoveGroup(MaxGroup);
538 m_SelectionPools[mode].RemoveGroup(MaxGroup);
540 // failed to build a selection pool matching the given values
541 return false;
544 // used to remove the Enter Battle window if the battle has already, but someone still has it
545 // (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event
546 void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
548 uint32 queue_id = bg->GetQueueType();
549 uint32 bgInstanceId = bg->GetInstanceID();
550 uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
551 QueuedGroupsList::iterator itr, next;
552 for(itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next)
554 // must do this way, because the groupinfo will be deleted when all playerinfos are removed
555 GroupQueueInfo * ginfo = (*itr);
556 next = itr;
557 ++next;
558 // if group was invited to this bg instance, then remove all references
559 if(ginfo->IsInvitedToBGInstanceGUID == bgInstanceId)
561 // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop
562 uint32 to_remove = ginfo->Players.size();
563 uint32 team = ginfo->Team;
564 for(int i = 0; i < to_remove; ++i)
566 // always remove the first one in the group
567 std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();
568 if(itr2 == ginfo->Players.end())
570 sLog.outError("Empty Players in ginfo, this should never happen!");
571 return;
574 // get the player
575 Player * plr = objmgr.GetPlayer(itr2->first);
576 if(!plr)
578 sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");
579 continue;
582 // get the queueslot
583 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
584 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
586 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
587 // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
588 RemovePlayer(itr2->first, true);
589 // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups
590 // but updateing the queue can't hurt
591 Update(bgQueueTypeId, bg->GetQueueType());
592 // send info to client
593 WorldPacket data;
594 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0);
595 plr->GetSession()->SendPacket(&data);
603 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
604 it must be called after fully adding the members of a group to ensure group joining
605 should be called after removeplayer functions in some cases
607 void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating)
609 if (queue_id >= MAX_BATTLEGROUND_QUEUES)
611 //this is error, that caused crashes (not in , but now it shouldn't)
612 sLog.outError("BattleGroundQueue::Update() called for non existing queue type - this can cause crash, pls report problem, if this is the last line of error log before crash");
613 return;
616 //if no players in queue ... do nothing
617 if (m_QueuedGroups[queue_id].empty())
618 return;
620 uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
622 //battleground with free slot for player should be always the last in this queue
623 BGFreeSlotQueueType::iterator itr, next;
624 for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
626 next = itr;
627 ++next;
628 // battleground is running, so if:
629 // DO NOT allow queue manager to invite new player to running arena
630 if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
632 //we must check both teams
633 BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
634 // and iterator is invalid
636 for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr)
638 // did the group join for this bg type?
639 if((*itr)->BgTypeId != bgTypeId)
640 continue;
641 // if so, check if fits in
642 if(bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size())
644 // if group fits in, invite it
645 InviteGroupToBG((*itr),bg,(*itr)->Team);
649 if (!bg->HasFreeSlots())
651 //remove BG from BGFreeSlotQueue
652 bg->RemoveFromBGFreeSlotQueue();
657 // finished iterating through the bgs with free slots, maybe we need to create a new bg
659 BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
660 if(!bg_template)
662 sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
663 return;
666 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
667 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
668 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
669 if(bg_template->isArena())
671 if(sBattleGroundMgr.isArenaTesting())
673 MaxPlayersPerTeam = 1;
674 MinPlayersPerTeam = 1;
676 else
678 switch(arenatype)
680 case ARENA_TYPE_2v2:
681 MaxPlayersPerTeam = 2;
682 MinPlayersPerTeam = 2;
683 break;
684 case ARENA_TYPE_3v3:
685 MaxPlayersPerTeam = 3;
686 MinPlayersPerTeam = 3;
687 break;
688 case ARENA_TYPE_5v5:
689 MaxPlayersPerTeam = 5;
690 MinPlayersPerTeam = 5;
691 break;
696 // found out the minimum and maximum ratings the newly added team should battle against
697 // arenaRating is the rating of the latest joined team
698 uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
699 // if no rating is specified, set maxrating to 0
700 uint32 arenaMaxRating = (arenaRating == 0)? 0 : arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
701 uint32 discardTime = 0;
702 // if max rating difference is set and the time past since server startup is greater than the rating discard time
703 // (after what time the ratings aren't taken into account when making teams) then
704 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
705 // else leave the discard time on 0, this way all ratings will be discarded
706 if(sBattleGroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattleGroundMgr.GetRatingDiscardTimer())
707 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
709 // try to build the selection pools
710 bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
711 if(bAllyOK)
712 sLog.outDebug("Battleground: ally pool succesfully build");
713 else
714 sLog.outDebug("Battleground: ally pool wasn't created");
715 bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
716 if(bHordeOK)
717 sLog.outDebug("Battleground: horde pool succesfully built");
718 else
719 sLog.outDebug("Battleground: horde pool wasn't created");
721 // if selection pools are ready, create the new bg
722 if (bAllyOK && bHordeOK)
724 BattleGround * bg2 = 0;
725 // special handling for arenas
726 if(bg_template->isArena())
728 // Find a random arena, that can be created
729 uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
730 uint32 arena_num = urand(0,2);
731 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
732 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
733 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
735 sLog.outError("Battleground: couldn't create any arena instance!");
736 return;
739 // set the MaxPlayersPerTeam values based on arenatype
740 // setting the min player values isn't needed, since we won't be using that value later on.
741 if(sBattleGroundMgr.isArenaTesting())
743 bg2->SetMaxPlayersPerTeam(1);
744 bg2->SetMaxPlayers(2);
746 else
748 switch(arenatype)
750 case ARENA_TYPE_2v2:
751 bg2->SetMaxPlayersPerTeam(2);
752 bg2->SetMaxPlayers(4);
753 break;
754 case ARENA_TYPE_3v3:
755 bg2->SetMaxPlayersPerTeam(3);
756 bg2->SetMaxPlayers(6);
757 break;
758 case ARENA_TYPE_5v5:
759 bg2->SetMaxPlayersPerTeam(5);
760 bg2->SetMaxPlayers(10);
761 break;
762 default:
763 break;
767 else
769 // create new battleground
770 bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId);
771 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
773 char const* bgName = bg2->GetName();
774 uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id);
775 uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id);
776 if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
777 q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
778 sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level);
782 if(!bg2)
784 sLog.outError("Battleground: couldn't create bg %u",bgTypeId);
785 return;
788 // start the joining of the bg
789 bg2->SetStatus(STATUS_WAIT_JOIN);
790 bg2->SetQueueType(queue_id);
791 // initialize arena / rating info
792 bg2->SetArenaType(arenatype);
793 // set rating
794 bg2->SetRated(isRated);
796 std::list<GroupQueueInfo* >::iterator itr;
798 // invite groups from horde selection pool
799 for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr)
801 InviteGroupToBG((*itr),bg2,HORDE);
804 // invite groups from ally selection pools
805 for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)
807 InviteGroupToBG((*itr),bg2,ALLIANCE);
810 if (isRated)
812 std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin();
813 std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin();
814 (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
815 sLog.outDebug("setting oposite teamrating for team %u to %u", (*itr_alliance)->ArenaTeamId, (*itr_alliance)->OpponentsTeamRating);
816 (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
817 sLog.outDebug("setting oposite teamrating for team %u to %u", (*itr_horde)->ArenaTeamId, (*itr_horde)->OpponentsTeamRating);
820 // start the battleground
821 bg2->StartBattleGround();
824 // there weren't enough players for a "normal" match
825 // if arena, enable horde versus horde or alliance versus alliance teams here
827 else if(bg_template->isArena())
829 bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false;
830 bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false;
831 bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
832 if(bOneSideHordeTeam1)
834 // one team has been selected, find out if other can be selected too
835 std::list<GroupQueueInfo* >::iterator itr;
836 // temporarily change the team side to enable building the next pool excluding the already selected groups
837 for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
838 (*itr)->Team=ALLIANCE;
840 bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime, (*(m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
842 // change back the team to horde
843 for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
844 (*itr)->Team=HORDE;
846 if(!bOneSideHordeTeam2)
847 bOneSideHordeTeam1 = false;
849 if(!bOneSideHordeTeam1)
851 // check for one sided ally
852 bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
853 if(bOneSideAllyTeam1)
855 // one team has been selected, find out if other can be selected too
856 std::list<GroupQueueInfo* >::iterator itr;
857 // temporarily change the team side to enable building the next pool excluding the already selected groups
858 for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
859 (*itr)->Team=HORDE;
861 bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime,(*(m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
863 // change back the team to ally
864 for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
865 (*itr)->Team=ALLIANCE;
868 if(!bOneSideAllyTeam2)
869 bOneSideAllyTeam1 = false;
871 // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!
872 if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) ||
873 (bOneSideAllyTeam1 && bOneSideAllyTeam2) )
875 // which side has enough players?
876 uint32 side = 0;
877 SelectionPoolBuildMode mode1, mode2;
878 // find out what pools are we using
879 if(bOneSideAllyTeam1 && bOneSideAllyTeam2)
881 side = ALLIANCE;
882 mode1 = ONESIDE_ALLIANCE_TEAM1;
883 mode2 = ONESIDE_ALLIANCE_TEAM2;
885 else
887 side = HORDE;
888 mode1 = ONESIDE_HORDE_TEAM1;
889 mode2 = ONESIDE_HORDE_TEAM2;
892 // create random arena
893 uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
894 uint32 arena_num = urand(0,2);
895 BattleGround* bg2 = NULL;
896 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
897 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
898 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
900 sLog.outError("Could not create arena.");
901 return;
904 sLog.outDebug("Battleground: One-faction arena created.");
905 // init stats
906 if(sBattleGroundMgr.isArenaTesting())
908 bg2->SetMaxPlayersPerTeam(1);
909 bg2->SetMaxPlayers(2);
911 else
913 switch(arenatype)
915 case ARENA_TYPE_2v2:
916 bg2->SetMaxPlayersPerTeam(2);
917 bg2->SetMaxPlayers(4);
918 break;
919 case ARENA_TYPE_3v3:
920 bg2->SetMaxPlayersPerTeam(3);
921 bg2->SetMaxPlayers(6);
922 break;
923 case ARENA_TYPE_5v5:
924 bg2->SetMaxPlayersPerTeam(5);
925 bg2->SetMaxPlayers(10);
926 break;
927 default:
928 break;
932 bg2->SetRated(isRated);
934 // assigned team of the other group
935 uint32 other_side;
936 if(side == ALLIANCE)
937 other_side = HORDE;
938 else
939 other_side = ALLIANCE;
941 // start the joining of the bg
942 bg2->SetStatus(STATUS_WAIT_JOIN);
943 bg2->SetQueueType(queue_id);
944 // initialize arena / rating info
945 bg2->SetArenaType(arenatype);
947 std::list<GroupQueueInfo* >::iterator itr;
949 // invite players from the first group as horde players (actually green team)
950 for(itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr)
952 InviteGroupToBG((*itr),bg2,HORDE);
955 // invite players from the second group as ally players (actually gold team)
956 for(itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr)
958 InviteGroupToBG((*itr),bg2,ALLIANCE);
961 if (isRated)
963 std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[mode1].SelectedGroups.begin();
964 std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[mode2].SelectedGroups.begin();
965 (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
966 (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
969 bg2->StartBattleGround();
974 /*********************************************************/
975 /*** BATTLEGROUND QUEUE EVENTS ***/
976 /*********************************************************/
978 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
980 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
982 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
983 if (!plr)
984 return true;
986 // Player can be in another BG queue and must be removed in normal way in any case
987 // // player is already in battleground ... do nothing (battleground queue status is deleted when player is teleported to BG)
988 // if (plr->GetBattleGroundId() > 0)
989 // return true;
991 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
992 if (!bg)
993 return true;
995 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());
996 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
998 uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
999 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1000 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1002 // 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
1003 BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
1004 BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
1005 if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1007 WorldPacket data;
1008 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0);
1009 plr->GetSession()->SendPacket(&data);
1013 return true; //event will be deleted
1016 void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
1018 //this should not be called
1019 sLog.outError("Battleground invite event ABORTED!");
1022 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1024 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
1025 if (!plr)
1026 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1027 return true;
1029 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
1030 if (!bg)
1031 return true;
1033 sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
1035 uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1036 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1037 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1039 // 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
1040 BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid);
1041 if (qMapItr != sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1043 if (qMapItr->second.GroupInfo->IsRated)
1045 ArenaTeam * at = objmgr.GetArenaTeamById(qMapItr->second.GroupInfo->ArenaTeamId);
1046 if (at)
1048 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(plr->GetGUID()), qMapItr->second.GroupInfo->OpponentsTeamRating);
1049 at->MemberLost(plr, qMapItr->second.GroupInfo->OpponentsTeamRating);
1050 at->SaveToDB();
1053 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
1054 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
1055 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgQueueTypeId, bg->GetQueueType());
1056 WorldPacket data;
1057 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0);
1058 plr->GetSession()->SendPacket(&data);
1061 else
1062 sLog.outDebug("Battleground: Player was already removed from queue");
1064 //event will be deleted
1065 return true;
1068 void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
1070 //this should not be called
1071 sLog.outError("Battleground remove event ABORTED!");
1074 /*********************************************************/
1075 /*** BATTLEGROUND MANAGER ***/
1076 /*********************************************************/
1078 BattleGroundMgr::BattleGroundMgr()
1080 m_BattleGrounds.clear();
1081 m_AutoDistributePoints = (bool)sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS);
1082 m_MaxRatingDifference = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
1083 m_RatingDiscardTimer = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1084 m_PrematureFinishTimer = sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
1085 m_NextRatingDiscardUpdate = m_RatingDiscardTimer;
1086 m_AutoDistributionTimeChecker = 0;
1087 m_ArenaTesting = false;
1090 BattleGroundMgr::~BattleGroundMgr()
1092 BattleGroundSet::iterator itr, next;
1093 for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
1095 next = itr;
1096 ++next;
1097 BattleGround * bg = itr->second;
1098 m_BattleGrounds.erase(itr);
1099 delete bg;
1101 m_BattleGrounds.clear();
1104 // used to update running battlegrounds, and delete finished ones
1105 void BattleGroundMgr::Update(time_t diff)
1107 BattleGroundSet::iterator itr, next;
1108 for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
1110 next = itr;
1111 ++next;
1112 itr->second->Update(diff);
1113 // use the SetDeleteThis variable
1114 // direct deletion caused crashes
1115 if(itr->second->m_SetDeleteThis)
1117 BattleGround * bg = itr->second;
1118 m_BattleGrounds.erase(itr);
1119 delete bg;
1122 // if rating difference counts, maybe force-update queues
1123 if(m_MaxRatingDifference)
1125 // it's time to force update
1126 if(m_NextRatingDiscardUpdate < diff)
1128 // forced update for level 70 rated arenas
1129 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA,6,ARENA_TYPE_2v2,true,0);
1130 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA,6,ARENA_TYPE_3v3,true,0);
1131 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA,6,ARENA_TYPE_5v5,true,0);
1132 m_NextRatingDiscardUpdate = m_RatingDiscardTimer;
1134 else
1135 m_NextRatingDiscardUpdate -= diff;
1137 if(m_AutoDistributePoints)
1139 if(m_AutoDistributionTimeChecker < diff)
1141 if(sWorld.GetGameTime() > m_NextAutoDistributionTime)
1143 DistributeArenaPoints();
1144 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1145 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"I64FMTD"'", m_NextAutoDistributionTime);
1147 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1149 else
1150 m_AutoDistributionTimeChecker -= diff;
1154 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted)
1156 // we can be in 3 queues in same time...
1157 if(StatusID == 0)
1159 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
1160 *data << uint32(QueueSlot); // queue id (0...2)
1161 *data << uint64(0);
1162 return;
1165 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
1166 *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1167 // uint64 in client
1168 *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1169 *data << uint32(0); // unknown
1170 // alliance/horde for BG and skirmish/rated for Arenas
1171 *data << uint8(bg->isArena() ? ( israted ? israted : bg->isRated() ) : bg->GetTeamIndexByTeamId(team));
1172 /* *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!!!!
1173 switch(bg->GetTypeID()) // value depends on bg id
1175 case BATTLEGROUND_AV:
1176 *data << uint8(1);
1177 break;
1178 case BATTLEGROUND_WS:
1179 *data << uint8(2);
1180 break;
1181 case BATTLEGROUND_AB:
1182 *data << uint8(3);
1183 break;
1184 case BATTLEGROUND_NA:
1185 *data << uint8(4);
1186 break;
1187 case BATTLEGROUND_BE:
1188 *data << uint8(5);
1189 break;
1190 case BATTLEGROUND_AA:
1191 *data << uint8(6);
1192 break;
1193 case BATTLEGROUND_EY:
1194 *data << uint8(7);
1195 break;
1196 case BATTLEGROUND_RL:
1197 *data << uint8(8);
1198 break;
1199 case BATTLEGROUND_SA:
1200 *data << uint8(9);
1201 break;
1202 case BATTLEGROUND_DS:
1203 *data << uint8(10);
1204 break;
1205 case BATTLEGROUND_RV:
1206 *data << uint8(11);
1207 break;
1208 default: // unknown
1209 *data << uint8(0);
1210 break;
1213 if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1214 *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1215 else
1216 *data << uint32(bg->GetTypeID()); // BG id from DBC
1218 *data << uint16(0x1F90); // unk value 8080
1219 *data << uint32(bg->GetInstanceID()); // instance id
1221 if(bg->isBattleGround())
1222 *data << uint8(bg->GetTeamIndexByTeamId(team)); // team
1223 else
1224 *data << uint8(israted?israted:bg->isRated()); // is rated battle
1226 *data << uint32(StatusID); // status
1227 switch(StatusID)
1229 case STATUS_WAIT_QUEUE: // status_in_queue
1230 *data << uint32(Time1); // average wait time, milliseconds
1231 *data << uint32(Time2); // time in queue, updated every minute?
1232 break;
1233 case STATUS_WAIT_JOIN: // status_invite
1234 *data << uint32(bg->GetMapId()); // map id
1235 *data << uint32(Time1); // time to remove from queue, milliseconds
1236 break;
1237 case STATUS_IN_PROGRESS: // status_in_progress
1238 *data << uint32(bg->GetMapId()); // map id
1239 *data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds
1240 *data << uint32(Time2); // time from bg start, milliseconds
1241 *data << uint8(0x1); // unk sometimes 0x0!
1242 break;
1243 default:
1244 sLog.outError("Unknown BG status!");
1245 break;
1249 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1251 uint8 type = (bg->isArena() ? 1 : 0);
1252 // last check on 2.4.1
1253 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1254 *data << uint8(type); // seems to be type (battleground=0/arena=1)
1256 if(type) // arena
1258 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1259 for(int i = 1; i >= 0; --i)
1261 *data << uint32(3000-bg->m_ArenaTeamRatingChanges[i]); // rating change: showed value - 3000
1262 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1263 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1265 for(int i = 1; i >= 0; --i)
1267 uint32 at_id = bg->m_ArenaTeamIds[i];
1268 ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
1269 if(at)
1270 *data << at->GetName();
1271 else//*/
1272 *data << (uint8)0;
1276 if(bg->GetWinner() == 2)
1278 *data << uint8(0); // bg in progress
1280 else
1282 *data << uint8(1); // bg ended
1283 *data << uint8(bg->GetWinner()); // who win
1286 *data << (int32)(bg->GetPlayerScoresSize());
1288 for(std::map<uint64, BattleGroundScore*>::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1290 *data << (uint64)itr->first;
1291 *data << (int32)itr->second->KillingBlows;
1292 Player *plr = objmgr.GetPlayer(itr->first);
1293 uint32 team = bg->GetPlayerTeam(itr->first);
1294 if(!team && plr) team = plr->GetTeam();
1295 if(type == 0)
1297 *data << (int32)itr->second->HonorableKills;
1298 *data << (int32)itr->second->Deaths;
1299 *data << (int32)(itr->second->BonusHonor);
1301 else
1303 // that part probably wrong
1304 if(plr)
1306 if(team == HORDE)
1307 *data << uint8(0);
1308 else if(team == ALLIANCE)
1310 *data << uint8(1);
1312 else
1313 *data << uint8(0);
1315 else
1316 *data << uint8(0);
1318 *data << (int32)itr->second->DamageDone; // damage done
1319 *data << (int32)itr->second->HealingDone; // healing done
1320 switch(bg->GetTypeID()) // battleground specific things
1322 case BATTLEGROUND_AV:
1323 *data << (uint32)0x00000005; // count of next fields
1324 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1325 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1326 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1327 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1328 *data << (uint32)((BattleGroundAVScore*)itr->second)->MinesCaptured; // MinesCaptured
1329 break;
1330 case BATTLEGROUND_WS:
1331 *data << (uint32)0x00000002; // count of next fields
1332 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1333 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1334 break;
1335 case BATTLEGROUND_AB:
1336 *data << (uint32)0x00000002; // count of next fields
1337 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1338 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1339 break;
1340 case BATTLEGROUND_EY:
1341 *data << (uint32)0x00000001; // count of next fields
1342 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1343 break;
1344 case BATTLEGROUND_NA:
1345 case BATTLEGROUND_BE:
1346 case BATTLEGROUND_AA:
1347 case BATTLEGROUND_RL:
1348 case BATTLEGROUND_SA: // wotlk
1349 case BATTLEGROUND_DS: // wotlk
1350 case BATTLEGROUND_RV: // wotlk
1351 *data << (int32)0; // 0
1352 break;
1353 default:
1354 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1355 *data << (int32)0;
1356 break;
1361 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, uint32 bgTypeId)
1363 /*bgTypeId is:
1364 0 - Your group has joined a battleground queue, but you are not eligible
1365 1 - Your group has joined the queue for AV
1366 2 - Your group has joined the queue for WS
1367 3 - Your group has joined the queue for AB
1368 4 - Your group has joined the queue for NA
1369 5 - Your group has joined the queue for BE Arena
1370 6 - Your group has joined the queue for All Arenas
1371 7 - Your group has joined the queue for EotS*/
1372 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1373 *data << uint32(bgTypeId);
1376 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1378 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1379 *data << uint32(field);
1380 *data << uint32(value);
1383 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1385 data->Initialize(SMSG_PLAY_SOUND, 4);
1386 *data << uint32(soundid);
1389 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, Player *plr)
1391 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1392 *data << uint64(plr->GetGUID());
1395 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1397 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1398 *data << uint64(plr->GetGUID());
1401 void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team)
1403 // set invited player counters:
1404 BattleGround* bg = GetBattleGround(bgInstanceGUID);
1405 if(!bg)
1406 return;
1407 bg->IncreaseInvitedCount(team);
1409 plr->SetInviteForBattleGroundQueueType(BGQueueTypeId(bg->GetTypeID(),bg->GetArenaType()), bgInstanceGUID);
1411 // set the arena teams for rated matches
1412 if(bg->isArena() && bg->isRated())
1414 switch(bg->GetArenaType())
1416 case ARENA_TYPE_2v2:
1417 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));
1418 break;
1419 case ARENA_TYPE_3v3:
1420 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));
1421 break;
1422 case ARENA_TYPE_5v5:
1423 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));
1424 break;
1425 default:
1426 break;
1430 // create invite events:
1431 //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
1432 BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID);
1433 plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME/2));
1434 BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team);
1435 plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
1438 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(uint32 bgTypeId)
1440 return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();
1443 // create a new battleground that will really be used to play
1444 BattleGround * BattleGroundMgr::CreateNewBattleGround(uint32 bgTypeId)
1446 BattleGround *bg = NULL;
1448 // get the template BG
1449 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1451 if(!bg_template)
1453 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1454 return 0;
1457 // create a copy of the BG template
1458 switch(bgTypeId)
1460 case BATTLEGROUND_AV:
1461 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1462 break;
1463 case BATTLEGROUND_WS:
1464 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1465 break;
1466 case BATTLEGROUND_AB:
1467 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1468 break;
1469 case BATTLEGROUND_NA:
1470 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1471 break;
1472 case BATTLEGROUND_BE:
1473 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1474 break;
1475 case BATTLEGROUND_AA:
1476 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1477 break;
1478 case BATTLEGROUND_EY:
1479 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1480 break;
1481 case BATTLEGROUND_RL:
1482 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1483 break;
1484 case BATTLEGROUND_SA:
1485 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1486 break;
1487 case BATTLEGROUND_DS:
1488 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1489 break;
1490 case BATTLEGROUND_RV:
1491 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1492 break;
1493 default:
1494 //bg = new BattleGround;
1495 return 0;
1496 break; // placeholder for non implemented BG
1499 // generate a new instance id
1500 bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
1502 // reset the new bg (set status to status_wait_queue from status_none)
1503 bg->Reset();
1505 /* will be setup in BG::Update() when the first player is ported in
1506 if(!(bg->SetupBattleGround()))
1508 sLog.outError("BattleGround: CreateNewBattleGround: SetupBattleGround failed for bg %u", bgTypeId);
1509 delete bg;
1510 return 0;
1514 // add BG to free slot queue
1515 bg->AddToBGFreeSlotQueue();
1517 // add bg to update list
1518 AddBattleGround(bg->GetInstanceID(), bg);
1520 return bg;
1523 // used to create the BG templates
1524 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)
1526 // Create the BG
1527 BattleGround *bg = NULL;
1529 switch(bgTypeId)
1531 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1532 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1533 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1534 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1535 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1536 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1537 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1538 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1539 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1540 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1541 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1542 default:bg = new BattleGround; break; // placeholder for non implemented BG
1545 bg->SetMapId(MapID);
1547 bg->Reset();
1549 BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId);
1550 //in previous method is checked if exists entry in sBattlemasterListStore, so no check needed
1551 if (bl)
1553 bg->SetArenaorBGType(bl->type == TYPE_ARENA);
1556 bg->SetTypeID(bgTypeId);
1557 bg->SetInstanceID(0); // template bg, instance id is 0
1558 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1559 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1560 bg->SetMinPlayers(MinPlayersPerTeam*2);
1561 bg->SetMaxPlayers(MaxPlayersPerTeam*2);
1562 bg->SetName(BattleGroundName);
1563 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1564 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1565 bg->SetLevelRange(LevelMin, LevelMax);
1567 //add BattleGround instance to FreeSlotQueue (.back() will return the template!)
1568 bg->AddToBGFreeSlotQueue();
1570 // do NOT add to update list, since this is a template battleground!
1572 // return some not-null value, bgTypeId is good enough for me
1573 return bgTypeId;
1576 void BattleGroundMgr::CreateInitialBattleGrounds()
1578 float AStartLoc[4];
1579 float HStartLoc[4];
1580 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1581 BattlemasterListEntry const *bl;
1582 WorldSafeLocsEntry const *start;
1584 uint32 count = 0;
1586 // 0 1 2 3 4 5 6 7 8
1587 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1589 if(!result)
1591 barGoLink bar(1);
1593 bar.step();
1595 sLog.outString();
1596 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1597 return;
1600 barGoLink bar(result->GetRowCount());
1604 Field *fields = result->Fetch();
1605 bar.step();
1607 uint32 bgTypeID = fields[0].GetUInt32();
1609 // can be overwrited by values from DB
1610 bl = sBattlemasterListStore.LookupEntry(bgTypeID);
1611 if(!bl)
1613 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.",bgTypeID);
1614 continue;
1617 MaxPlayersPerTeam = bl->maxplayersperteam;
1618 MinPlayersPerTeam = bl->maxplayersperteam/2;
1619 MinLvl = bl->minlvl;
1620 MaxLvl = bl->maxlvl;
1622 if(fields[1].GetUInt32())
1623 MinPlayersPerTeam = fields[1].GetUInt32();
1625 if(fields[2].GetUInt32())
1626 MaxPlayersPerTeam = fields[2].GetUInt32();
1628 if(fields[3].GetUInt32())
1629 MinLvl = fields[3].GetUInt32();
1631 if(fields[4].GetUInt32())
1632 MaxLvl = fields[4].GetUInt32();
1634 start1 = fields[5].GetUInt32();
1636 start = sWorldSafeLocsStore.LookupEntry(start1);
1637 if(start)
1639 AStartLoc[0] = start->x;
1640 AStartLoc[1] = start->y;
1641 AStartLoc[2] = start->z;
1642 AStartLoc[3] = fields[6].GetFloat();
1644 else if(bgTypeID == BATTLEGROUND_AA)
1646 AStartLoc[0] = 0;
1647 AStartLoc[1] = 0;
1648 AStartLoc[2] = 0;
1649 AStartLoc[3] = fields[6].GetFloat();
1651 else
1653 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.",bgTypeID,start1);
1654 continue;
1657 start2 = fields[7].GetUInt32();
1659 start = sWorldSafeLocsStore.LookupEntry(start2);
1660 if(start)
1662 HStartLoc[0] = start->x;
1663 HStartLoc[1] = start->y;
1664 HStartLoc[2] = start->z;
1665 HStartLoc[3] = fields[8].GetFloat();
1667 else if(bgTypeID == BATTLEGROUND_AA)
1669 HStartLoc[0] = 0;
1670 HStartLoc[1] = 0;
1671 HStartLoc[2] = 0;
1672 HStartLoc[3] = fields[8].GetFloat();
1674 else
1676 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.",bgTypeID,start2);
1677 continue;
1680 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1681 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]))
1682 continue;
1684 ++count;
1685 } while (result->NextRow());
1687 delete result;
1689 sLog.outString();
1690 sLog.outString( ">> Loaded %u battlegrounds", count );
1693 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1695 if(m_AutoDistributePoints)
1697 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1698 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1699 if(!result)
1701 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1702 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1703 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"I64FMTD"')", m_NextAutoDistributionTime);
1705 else
1707 m_NextAutoDistributionTime = (*result)[0].GetUInt64();
1708 delete result;
1710 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1714 void BattleGroundMgr::DistributeArenaPoints()
1716 // used to distribute arena points based on last week's stats
1717 sWorld.SendGlobalText("Flushing Arena points based on team ratings, this may take a few minutes. Please stand by...", NULL);
1719 sWorld.SendGlobalText("Distributing arena points to players...", NULL);
1721 //temporary structure for storing maximum points to add values for all players
1722 std::map<uint32, uint32> PlayerPoints;
1724 //at first update all points for all team members
1725 for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
1727 if(ArenaTeam * at = team_itr->second)
1729 at->UpdateArenaPointsHelper(PlayerPoints);
1733 //cycle that gives points to all players
1734 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1736 //update to database
1737 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE `guid` = '%u'", plr_itr->second, plr_itr->first);
1738 //add points if player is online
1739 Player* pl = objmgr.GetPlayer(plr_itr->first);
1740 if (pl)
1741 pl->ModifyArenaPoints(plr_itr->second);
1744 PlayerPoints.clear();
1746 sWorld.SendGlobalText("Finished setting arena points for online players.", NULL);
1748 sWorld.SendGlobalText("Modifying played count, arena points etc. for loaded arena teams, sending updated stats to online players...", NULL);
1749 for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
1751 if(ArenaTeam * at = titr->second)
1753 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1754 at->SaveToDB(); // save changes
1755 at->NotifyStatsChanged(); // notify the players of the changes
1759 sWorld.SendGlobalText("Modification done.", NULL);
1761 sWorld.SendGlobalText("Done flushing Arena points.", NULL);
1764 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player* plr, uint32 bgTypeId)
1766 uint32 PlayerLevel = 10;
1768 if(plr)
1769 PlayerLevel = plr->getLevel();
1771 data->Initialize(SMSG_BATTLEFIELD_LIST);
1772 *data << uint64(guid); // battlemaster guid
1773 *data << uint32(bgTypeId); // battleground id
1774 if(bgTypeId == BATTLEGROUND_AA) // arena
1776 *data << uint8(5); // unk
1777 *data << uint32(0); // unk
1779 else // battleground
1781 *data << uint8(0x00); // unk
1783 size_t count_pos = data->wpos();
1784 uint32 count = 0;
1785 *data << uint32(0x00); // number of bg instances
1787 for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
1789 if(itr->second->GetTypeID() == bgTypeId && (PlayerLevel >= itr->second->GetMinLevel()) && (PlayerLevel <= itr->second->GetMaxLevel()))
1791 *data << uint32(itr->second->GetInstanceID());
1792 ++count;
1795 data->put<uint32>( count_pos , count);
1799 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId)
1801 BattleGround *bg = GetBattleGround(instanceId);
1802 if(bg)
1804 uint32 mapid = bg->GetMapId();
1805 float x, y, z, O;
1806 uint32 team = pl->GetBGTeam();
1807 if(team==0)
1808 team = pl->GetTeam();
1809 bg->GetTeamStartLoc(team, x, y, z, O);
1811 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1812 pl->TeleportTo(mapid, x, y, z, O);
1814 else
1816 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1820 void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid)
1822 WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
1823 uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
1824 if(time_ == uint32(-1))
1825 time_ = 0;
1826 data << guid << time_;
1827 pl->GetSession()->SendPacket(&data);
1830 void BattleGroundMgr::RemoveBattleGround(uint32 instanceID)
1832 BattleGroundSet::iterator itr = m_BattleGrounds.find(instanceID);
1833 if(itr!=m_BattleGrounds.end())
1834 m_BattleGrounds.erase(itr);
1837 bool BattleGroundMgr::IsArenaType(uint32 bgTypeId) const
1839 return ( bgTypeId == BATTLEGROUND_AA ||
1840 bgTypeId == BATTLEGROUND_BE ||
1841 bgTypeId == BATTLEGROUND_NA ||
1842 bgTypeId == BATTLEGROUND_RL );
1845 bool BattleGroundMgr::IsBattleGroundType(uint32 bgTypeId) const
1847 return !IsArenaType(bgTypeId);
1850 uint32 BattleGroundMgr::BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const
1852 switch(bgTypeId)
1854 case BATTLEGROUND_WS:
1855 return BATTLEGROUND_QUEUE_WS;
1856 case BATTLEGROUND_AB:
1857 return BATTLEGROUND_QUEUE_AB;
1858 case BATTLEGROUND_AV:
1859 return BATTLEGROUND_QUEUE_AV;
1860 case BATTLEGROUND_EY:
1861 return BATTLEGROUND_QUEUE_EY;
1862 case BATTLEGROUND_SA:
1863 return BATTLEGROUND_QUEUE_SA;
1864 case BATTLEGROUND_AA:
1865 case BATTLEGROUND_NA:
1866 case BATTLEGROUND_RL:
1867 case BATTLEGROUND_BE:
1868 case BATTLEGROUND_DS:
1869 case BATTLEGROUND_RV:
1870 switch(arenaType)
1872 case ARENA_TYPE_2v2:
1873 return BATTLEGROUND_QUEUE_2v2;
1874 case ARENA_TYPE_3v3:
1875 return BATTLEGROUND_QUEUE_3v3;
1876 case ARENA_TYPE_5v5:
1877 return BATTLEGROUND_QUEUE_5v5;
1878 default:
1879 return 0;
1881 default:
1882 return 0;
1886 uint32 BattleGroundMgr::BGTemplateId(uint32 bgQueueTypeId) const
1888 switch(bgQueueTypeId)
1890 case BATTLEGROUND_QUEUE_WS:
1891 return BATTLEGROUND_WS;
1892 case BATTLEGROUND_QUEUE_AB:
1893 return BATTLEGROUND_AB;
1894 case BATTLEGROUND_QUEUE_AV:
1895 return BATTLEGROUND_AV;
1896 case BATTLEGROUND_QUEUE_EY:
1897 return BATTLEGROUND_EY;
1898 case BATTLEGROUND_QUEUE_SA:
1899 return BATTLEGROUND_SA;
1900 case BATTLEGROUND_QUEUE_2v2:
1901 case BATTLEGROUND_QUEUE_3v3:
1902 case BATTLEGROUND_QUEUE_5v5:
1903 return BATTLEGROUND_AA;
1904 default:
1905 return 0;
1909 uint8 BattleGroundMgr::BGArenaType(uint32 bgQueueTypeId) const
1911 switch(bgQueueTypeId)
1913 case BATTLEGROUND_QUEUE_2v2:
1914 return ARENA_TYPE_2v2;
1915 case BATTLEGROUND_QUEUE_3v3:
1916 return ARENA_TYPE_3v3;
1917 case BATTLEGROUND_QUEUE_5v5:
1918 return ARENA_TYPE_5v5;
1919 default:
1920 return 0;
1924 void BattleGroundMgr::ToggleArenaTesting()
1926 m_ArenaTesting = !m_ArenaTesting;
1927 if(m_ArenaTesting)
1928 sWorld.SendGlobalText("Arenas are set to 1v1 for debugging. So, don't join as group.", NULL);
1929 else
1930 sWorld.SendGlobalText("Arenas are set to normal playercount.", NULL);