[7297] Fixed profession spells sorting in trainer spell list at client.
[getmangos.git] / src / game / BattleGroundMgr.cpp
blob061192845437327bb5b30f3643893f078d332e5e
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "SharedDefines.h"
21 #include "Player.h"
22 #include "BattleGroundMgr.h"
23 #include "BattleGroundAV.h"
24 #include "BattleGroundAB.h"
25 #include "BattleGroundEY.h"
26 #include "BattleGroundWS.h"
27 #include "BattleGroundNA.h"
28 #include "BattleGroundBE.h"
29 #include "BattleGroundAA.h"
30 #include "BattleGroundRL.h"
31 #include "BattleGroundSA.h"
32 #include "BattleGroundDS.h"
33 #include "BattleGroundRV.h"
34 #include "MapManager.h"
35 #include "Map.h"
36 #include "MapInstanced.h"
37 #include "ObjectMgr.h"
38 #include "ProgressBar.h"
39 #include "Chat.h"
40 #include "ArenaTeam.h"
41 #include "World.h"
42 #include "WorldPacket.h"
43 #include "ProgressBar.h"
45 #include "Policies/SingletonImp.h"
47 INSTANTIATE_SINGLETON_1( BattleGroundMgr );
49 /*********************************************************/
50 /*** BATTLEGROUND QUEUE SYSTEM ***/
51 /*********************************************************/
53 BattleGroundQueue::BattleGroundQueue()
55 //queues are empty, we don't have to call clear()
58 BattleGroundQueue::~BattleGroundQueue()
60 for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
62 m_QueuedPlayers[i].clear();
63 for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr)
65 delete (*itr);
67 m_QueuedGroups[i].clear();
71 // initialize eligible groups from the given source matching the given specifications
72 void BattleGroundQueue::EligibleGroups::Init(BattleGroundQueue::QueuedGroupsList *source, BattleGroundTypeId BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType, bool IsRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam)
74 // clear from prev initialization
75 clear();
76 BattleGroundQueue::QueuedGroupsList::iterator itr, next;
77 // iterate through the source
78 for(itr = source->begin(); itr!= source->end(); itr = next)
80 next = itr;
81 ++next;
82 if( (*itr)->BgTypeId == BgTypeId && // bg type must match
83 (*itr)->ArenaType == ArenaType && // arena type must match
84 (*itr)->IsRated == IsRated && // israted must match
85 (*itr)->IsInvitedToBGInstanceGUID == 0 && // leave out already invited groups
86 (*itr)->Team == side && // match side
87 (*itr)->Players.size() <= MaxPlayers && // the group must fit in the bg
88 ( !excludeTeam || (*itr)->ArenaTeamId != excludeTeam ) && // if excludeTeam is specified, leave out those arena team ids
89 ( !IsRated || (*itr)->Players.size() == MaxPlayers ) && // if rated, then pass only if the player count is exact NEEDS TESTING! (but now this should never happen)
90 ( (*itr)->JoinTime <= DisregardTime // pass if disregard time is greater than join time
91 || (*itr)->ArenaTeamRating == 0 // pass if no rating info
92 || ( (*itr)->ArenaTeamRating >= MinRating // pass if matches the rating range
93 && (*itr)->ArenaTeamRating <= MaxRating ) ) )
95 // the group matches the conditions
96 // insert it in order of groupsize, and join time
97 uint32 size = (*itr)->Players.size();
98 uint32 jointime = (*itr)->JoinTime;
99 bool inserted = false;
101 for(std::list<GroupQueueInfo *>::iterator elig_itr = begin(); elig_itr != end(); ++elig_itr)
103 // if the next one's size is smaller, then insert
104 // also insert if the next one's size is equal, but it joined the queue later
105 if( ((*elig_itr)->Players.size()<size) ||
106 ((*elig_itr)->Players.size() == size && (*elig_itr)->JoinTime > jointime) )
108 insert(elig_itr,(*itr));
109 inserted = true;
110 break;
113 // if not inserted -> this is the smallest group -> push_back
114 if(!inserted)
116 push_back((*itr));
122 // remove group from eligible groups
123 // used when building selection pools
124 void BattleGroundQueue::EligibleGroups::RemoveGroup(GroupQueueInfo * ginfo)
126 for(std::list<GroupQueueInfo *>::iterator itr = begin(); itr != end(); ++itr)
128 if((*itr)==ginfo)
130 erase(itr);
131 return;
136 // selection pool initialization, used to clean up from prev selection
137 void BattleGroundQueue::SelectionPool::Init()
139 SelectedGroups.clear();
140 MaxGroup = 0;
141 PlayerCount = 0;
144 // get the maximal group from the selection pool
145 // used when building the pool, and have to remove the largest
146 GroupQueueInfo * BattleGroundQueue::SelectionPool::GetMaximalGroup()
148 if(SelectedGroups.empty())
150 sLog.outError("Getting max group when selection pool is empty, this should never happen.");
151 MaxGroup = NULL;
152 return 0;
154 // actually select the max group if it's not set
155 if(MaxGroup==0 && !SelectedGroups.empty())
157 uint32 max_size = 0;
158 for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
160 if(max_size<(*itr)->Players.size())
162 MaxGroup =(*itr);
163 max_size = MaxGroup->Players.size();
167 return MaxGroup;
170 // remove group info from selection pool
171 // used when building selection pools and have to remove maximal group
172 void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)
174 // uninitiate max group info if needed
175 if(MaxGroup == ginfo)
176 MaxGroup = 0;
177 // find what to remove
178 for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
180 if((*itr)==ginfo)
182 SelectedGroups.erase(itr);
183 // decrease selected players count
184 PlayerCount -= ginfo->Players.size();
185 return;
190 // add group to selection
191 // used when building selection pools
192 void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)
194 SelectedGroups.push_back(ginfo);
195 // increase selected players count
196 PlayerCount+=ginfo->Players.size();
197 if(!MaxGroup || ginfo->Players.size() > MaxGroup->Players.size())
199 // update max group info if needed
200 MaxGroup = ginfo;
204 // add group to bg queue with the given leader and bg specifications
205 GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating, uint32 arenateamid)
207 uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel(BgTypeId);
209 // create new ginfo
210 // cannot use the method like in addplayer, because that could modify an in-queue group's stats
211 // (e.g. leader leaving queue then joining as individual again)
212 GroupQueueInfo* ginfo = new GroupQueueInfo;
213 ginfo->BgTypeId = BgTypeId;
214 ginfo->ArenaType = ArenaType;
215 ginfo->ArenaTeamId = arenateamid;
216 ginfo->IsRated = isRated;
217 ginfo->IsInvitedToBGInstanceGUID = 0; // maybe this should be modifiable by function arguments to enable selection of running instances?
218 ginfo->JoinTime = getMSTime();
219 ginfo->Team = leader->GetTeam();
220 ginfo->ArenaTeamRating = arenaRating;
221 ginfo->OpponentsTeamRating = 0; //initialize it to 0
223 ginfo->Players.clear();
225 m_QueuedGroups[queue_id].push_back(ginfo);
227 // return ginfo, because it is needed to add players to this group info
228 return ginfo;
231 void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
233 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(ginfo->BgTypeId);
235 //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
236 PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()];
237 info.InviteTime = 0;
238 info.LastInviteTime = 0;
239 info.LastOnlineTime = getMSTime();
240 info.GroupInfo = ginfo;
242 // add the pinfo to ginfo's list
243 ginfo->Players[plr->GetGUID()] = &info;
246 void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
248 Player *plr = objmgr.GetPlayer(guid);
250 int32 queue_id = 0; // signed for proper for-loop finish
251 QueuedPlayersMap::iterator itr;
253 // mostly people with the highest levels are in battlegrounds, thats why
254 // we count from MAX_BATTLEGROUND_QUEUES to 0
255 for (queue_id = MAX_BATTLEGROUND_QUEUES-1; queue_id >= 0; queue_id--)
257 itr = m_QueuedPlayers[queue_id].find(guid);
258 if(itr != m_QueuedPlayers[queue_id].end())
259 break;
262 // couldn't find the player in bg queue, return
263 if(itr == m_QueuedPlayers[queue_id].end())
265 sLog.outError("Battleground: couldn't find player to remove.");
266 return;
269 GroupQueueInfo* group = itr->second.GroupInfo;
271 QueuedGroupsList::iterator group_itr = m_QueuedGroups[queue_id].begin();
272 for(; group_itr != m_QueuedGroups[queue_id].end(); ++group_itr)
274 if(group == *group_itr)
275 break;
278 // variables are set (what about leveling up when in queue????
279 // iterate through all queue_ids this isn't bad for us)
280 // remove player from group
281 // if only player there, remove group
283 // remove player queue info from group queue info
284 std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
286 if(pitr != group->Players.end())
287 group->Players.erase(pitr);
289 // check for iterator correctness
290 if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())
292 // used when player left the queue, NOT used when porting to bg
293 if (decreaseInvitedCount)
295 // if invited to bg, and should decrease invited count, then do it
296 if(group->IsInvitedToBGInstanceGUID)
298 BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID);
299 if (bg)
300 bg->DecreaseInvitedCount(group->Team);
301 if (bg && !bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE))
303 // no more players on battleground, set delete it
304 bg->SetDeleteThis();
307 // update the join queue, maybe now the player's group fits in a queue!
308 // not yet implemented (should store bgTypeId in group queue info?)
310 // remove player queue info
311 m_QueuedPlayers[queue_id].erase(itr);
312 // remove group queue info if needed
314 //if we left BG queue(not porting) OR if arena team left queue for rated match
315 if((decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()))
316 AnnounceWorld(group, guid, false);
318 if(group->Players.empty())
320 m_QueuedGroups[queue_id].erase(group_itr);
321 delete group;
323 // NEEDS TESTING!
324 // group wasn't empty, so it wasn't deleted, and player have left a rated queue -> everyone from the group should leave too
325 // don't remove recursively if already invited to bg!
326 else if(!group->IsInvitedToBGInstanceGUID && decreaseInvitedCount && group->IsRated)
328 // remove next player, this is recursive
329 // first send removal information
330 if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
332 BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
333 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId,group->ArenaType);
334 uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
335 plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
336 WorldPacket data;
337 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr2->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
338 plr2->GetSession()->SendPacket(&data);
340 // then actually delete, this may delete the group as well!
341 RemovePlayer(group->Players.begin()->first,decreaseInvitedCount);
346 void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue)
349 if(ginfo->ArenaType) //if Arena
351 if( sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated)
353 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
354 if(!bg)
355 return;
357 char const* bgName = bg->GetName();
358 if(isAddedToQueue)
359 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
360 else
361 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
364 else //if BG
366 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
368 Player *plr = objmgr.GetPlayer(playerGUID);
369 if(!plr)
370 return;
372 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
373 if(!bg)
374 return;
376 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID());
377 char const* bgName = bg->GetName();
379 uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id, ginfo->BgTypeId);
380 uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id, ginfo->BgTypeId);
382 // replace hardcoded max level by player max level for nice output
383 if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
384 q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
386 int8 MinPlayers = bg->GetMinPlayersPerTeam();
388 uint8 qHorde = 0;
389 uint8 qAlliance = 0;
391 BattleGroundTypeId bgTypeId = ginfo->BgTypeId;
392 QueuedPlayersMap::iterator itr;
393 for(itr = m_QueuedPlayers[queue_id].begin(); itr!= m_QueuedPlayers[queue_id].end(); ++itr)
395 if(itr->second.GroupInfo->BgTypeId == bgTypeId)
397 switch(itr->second.GroupInfo->Team)
399 case HORDE:
400 qHorde++; break;
401 case ALLIANCE:
402 qAlliance++; break;
403 default:
404 break;
409 // Show queue status to player only (when joining queue)
410 if(sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
412 ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
413 bgName, q_min_level, q_max_level, qAlliance, MinPlayers, qHorde, MinPlayers);
415 // System message
416 else
418 sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
419 bgName, q_min_level, q_max_level, qAlliance, MinPlayers, qHorde, MinPlayers);
425 bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
427 // set side if needed
428 if(side)
429 ginfo->Team = side;
431 if(!ginfo->IsInvitedToBGInstanceGUID)
433 // not yet invited
434 // set invitation
435 ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
436 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
437 // loop through the players
438 for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
440 // set status
441 itr->second->InviteTime = getMSTime();
442 itr->second->LastInviteTime = getMSTime();
444 // get the player
445 Player* plr = objmgr.GetPlayer(itr->first);
446 // if offline, skip him
447 if(!plr)
448 continue;
450 // invite the player
451 sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team);
453 WorldPacket data;
455 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
457 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());
459 // send status packet
460 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, side?side:plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
461 plr->GetSession()->SendPacket(&data);
463 return true;
466 return false;
469 // this function is responsible for the selection of queued groups when trying to create new battlegrounds
470 bool BattleGroundQueue::BuildSelectionPool(BattleGroundTypeId bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType, bool isRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam)
472 uint32 side;
473 switch(mode)
475 case NORMAL_ALLIANCE:
476 case ONESIDE_ALLIANCE_TEAM1:
477 case ONESIDE_ALLIANCE_TEAM2:
478 side = ALLIANCE;
479 break;
480 case NORMAL_HORDE:
481 case ONESIDE_HORDE_TEAM1:
482 case ONESIDE_HORDE_TEAM2:
483 side = HORDE;
484 break;
485 default:
486 //unknown mode, return false
487 sLog.outDebug("Battleground: unknown selection pool build mode, returning...");
488 return false;
491 // inititate the groups eligible to create the bg
492 m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime, excludeTeam);
493 // init the selected groups (clear)
494 m_SelectionPools[mode].Init();
495 while(!(m_EligibleGroups.empty()))
497 sLog.outDebug("m_EligibleGroups is not empty, continue building selection pool");
498 // in decreasing group size, add groups to join if they fit in the MaxPlayersPerTeam players
499 for(EligibleGroups::iterator itr= m_EligibleGroups.begin(); itr!=m_EligibleGroups.end(); ++itr)
501 // get the maximal not yet checked group
502 GroupQueueInfo * MaxGroup = (*itr);
503 // if it fits in the maxplayer size, add it
504 if( (m_SelectionPools[mode].GetPlayerCount() + MaxGroup->Players.size()) <= MaxPlayers )
506 m_SelectionPools[mode].AddGroup(MaxGroup);
509 if(m_SelectionPools[mode].GetPlayerCount()>=MinPlayers)
511 // the selection pool is set, return
512 sLog.outDebug("pool build succeeded, return true");
513 return true;
515 // if the selection pool's not set, then remove the group with the highest player count, and try again with the rest.
516 GroupQueueInfo * MaxGroup = m_SelectionPools[mode].GetMaximalGroup();
517 m_EligibleGroups.RemoveGroup(MaxGroup);
518 m_SelectionPools[mode].RemoveGroup(MaxGroup);
520 // failed to build a selection pool matching the given values
521 return false;
524 // used to remove the Enter Battle window if the battle has already, but someone still has it
525 // (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event
526 void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
528 uint32 queue_id = bg->GetQueueId();
529 uint32 bgInstanceId = bg->GetInstanceID();
530 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
531 QueuedGroupsList::iterator itr, next;
532 for(itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next)
534 // must do this way, because the groupinfo will be deleted when all playerinfos are removed
535 GroupQueueInfo * ginfo = (*itr);
536 next = itr;
537 ++next;
538 // if group was invited to this bg instance, then remove all references
539 if(ginfo->IsInvitedToBGInstanceGUID == bgInstanceId)
541 // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop
542 uint32 to_remove = ginfo->Players.size();
543 uint32 team = ginfo->Team;
544 for(int i = 0; i < to_remove; ++i)
546 // always remove the first one in the group
547 std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();
548 if(itr2 == ginfo->Players.end())
550 sLog.outError("Empty Players in ginfo, this should never happen!");
551 return;
554 // get the player
555 Player * plr = objmgr.GetPlayer(itr2->first);
556 if(!plr)
558 sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");
559 continue;
562 // get the queueslot
563 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
564 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
566 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
567 // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
568 RemovePlayer(itr2->first, true);
569 // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups
570 // but updateing the queue can't hurt
571 Update(bg->GetTypeID(), bg->GetQueueId());
572 // send info to client
573 WorldPacket data;
574 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0);
575 plr->GetSession()->SendPacket(&data);
583 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
584 it must be called after fully adding the members of a group to ensure group joining
585 should be called after removeplayer functions in some cases
587 void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating)
589 if (queue_id >= MAX_BATTLEGROUND_QUEUES)
591 //this is error, that caused crashes (not in , but now it shouldn't)
592 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");
593 return;
596 //if no players in queue ... do nothing
597 if (m_QueuedGroups[queue_id].empty())
598 return;
600 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype);
602 //battleground with free slot for player should be always the last in this queue
603 BGFreeSlotQueueType::iterator itr, next;
604 for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
606 next = itr;
607 ++next;
608 // battleground is running, so if:
609 // DO NOT allow queue manager to invite new player to running arena
610 if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueId() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
612 //we must check both teams
613 BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
614 // and iterator is invalid
616 for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr)
618 // did the group join for this bg type?
619 if((*itr)->BgTypeId != bgTypeId)
620 continue;
621 // if so, check if fits in
622 if(bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size())
624 // if group fits in, invite it
625 InviteGroupToBG((*itr),bg,(*itr)->Team);
629 if (!bg->HasFreeSlots())
631 //remove BG from BGFreeSlotQueue
632 bg->RemoveFromBGFreeSlotQueue();
637 // finished iterating through the bgs with free slots, maybe we need to create a new bg
639 BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
640 if(!bg_template)
642 sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
643 return;
646 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
647 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
648 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
649 if(bg_template->isArena())
651 if(sBattleGroundMgr.isArenaTesting())
653 MaxPlayersPerTeam = 1;
654 MinPlayersPerTeam = 1;
656 else
658 switch(arenatype)
660 case ARENA_TYPE_2v2:
661 MaxPlayersPerTeam = 2;
662 MinPlayersPerTeam = 2;
663 break;
664 case ARENA_TYPE_3v3:
665 MaxPlayersPerTeam = 3;
666 MinPlayersPerTeam = 3;
667 break;
668 case ARENA_TYPE_5v5:
669 MaxPlayersPerTeam = 5;
670 MinPlayersPerTeam = 5;
671 break;
675 // BG case
676 else
678 if(sBattleGroundMgr.isTesting())
680 MinPlayersPerTeam = 1;
684 // found out the minimum and maximum ratings the newly added team should battle against
685 // arenaRating is the rating of the latest joined team
686 uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
687 // if no rating is specified, set maxrating to 0
688 uint32 arenaMaxRating = (arenaRating == 0)? 0 : arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
689 uint32 discardTime = 0;
690 // if max rating difference is set and the time past since server startup is greater than the rating discard time
691 // (after what time the ratings aren't taken into account when making teams) then
692 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
693 // else leave the discard time on 0, this way all ratings will be discarded
694 if(sBattleGroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattleGroundMgr.GetRatingDiscardTimer())
695 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
697 // try to build the selection pools
698 bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
699 if(bAllyOK)
700 sLog.outDebug("Battleground: ally pool succesfully build");
701 else
702 sLog.outDebug("Battleground: ally pool wasn't created");
703 bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
704 if(bHordeOK)
705 sLog.outDebug("Battleground: horde pool succesfully built");
706 else
707 sLog.outDebug("Battleground: horde pool wasn't created");
709 // if selection pools are ready, create the new bg
710 if ((bAllyOK && bHordeOK) || ( sBattleGroundMgr.isTesting() && (bAllyOK || bHordeOK)))
712 BattleGround * bg2 = 0;
713 // special handling for arenas
714 if(bg_template->isArena())
716 // Find a random arena, that can be created
717 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
718 uint32 arena_num = urand(0,2);
719 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
720 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
721 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
723 sLog.outError("Battleground: couldn't create any arena instance!");
724 return;
727 // set the MaxPlayersPerTeam values based on arenatype
728 // setting the min player values isn't needed, since we won't be using that value later on.
729 if(sBattleGroundMgr.isArenaTesting())
731 bg2->SetMaxPlayersPerTeam(1);
732 bg2->SetMaxPlayers(2);
734 else
736 switch(arenatype)
738 case ARENA_TYPE_2v2:
739 bg2->SetMaxPlayersPerTeam(2);
740 bg2->SetMaxPlayers(4);
741 break;
742 case ARENA_TYPE_3v3:
743 bg2->SetMaxPlayersPerTeam(3);
744 bg2->SetMaxPlayers(6);
745 break;
746 case ARENA_TYPE_5v5:
747 bg2->SetMaxPlayersPerTeam(5);
748 bg2->SetMaxPlayers(10);
749 break;
750 default:
751 break;
755 else
757 // create new battleground
758 bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId);
759 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
761 char const* bgName = bg2->GetName();
762 uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id, bgTypeId);
763 uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id, bgTypeId);
764 if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
765 q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
766 sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level);
770 if(!bg2)
772 sLog.outError("Battleground: couldn't create bg %u",bgTypeId);
773 return;
776 // start the joining of the bg
777 bg2->SetStatus(STATUS_WAIT_JOIN);
778 bg2->SetQueueId(queue_id);
779 // initialize arena / rating info
780 bg2->SetArenaType(arenatype);
781 // set rating
782 bg2->SetRated(isRated);
784 std::list<GroupQueueInfo* >::iterator itr;
786 // invite groups from horde selection pool
787 for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr)
789 InviteGroupToBG((*itr),bg2,HORDE);
792 // invite groups from ally selection pools
793 for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)
795 InviteGroupToBG((*itr),bg2,ALLIANCE);
798 if (isRated)
800 std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin();
801 std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin();
802 (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
803 sLog.outDebug("setting oposite teamrating for team %u to %u", (*itr_alliance)->ArenaTeamId, (*itr_alliance)->OpponentsTeamRating);
804 (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
805 sLog.outDebug("setting oposite teamrating for team %u to %u", (*itr_horde)->ArenaTeamId, (*itr_horde)->OpponentsTeamRating);
808 // start the battleground
809 bg2->StartBattleGround();
812 // there weren't enough players for a "normal" match
813 // if arena, enable horde versus horde or alliance versus alliance teams here
815 else if(bg_template->isArena())
817 bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false;
818 bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false;
819 bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
820 if(bOneSideHordeTeam1)
822 // one team has been selected, find out if other can be selected too
823 std::list<GroupQueueInfo* >::iterator itr;
824 // temporarily change the team side to enable building the next pool excluding the already selected groups
825 for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
826 (*itr)->Team=ALLIANCE;
828 bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime, (*(m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
830 // change back the team to horde
831 for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
832 (*itr)->Team=HORDE;
834 if(!bOneSideHordeTeam2)
835 bOneSideHordeTeam1 = false;
837 if(!bOneSideHordeTeam1)
839 // check for one sided ally
840 bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
841 if(bOneSideAllyTeam1)
843 // one team has been selected, find out if other can be selected too
844 std::list<GroupQueueInfo* >::iterator itr;
845 // temporarily change the team side to enable building the next pool excluding the already selected groups
846 for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
847 (*itr)->Team=HORDE;
849 bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime,(*(m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
851 // change back the team to ally
852 for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
853 (*itr)->Team=ALLIANCE;
856 if(!bOneSideAllyTeam2)
857 bOneSideAllyTeam1 = false;
859 // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!
860 if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) ||
861 (bOneSideAllyTeam1 && bOneSideAllyTeam2) )
863 // which side has enough players?
864 uint32 side = 0;
865 SelectionPoolBuildMode mode1, mode2;
866 // find out what pools are we using
867 if(bOneSideAllyTeam1 && bOneSideAllyTeam2)
869 side = ALLIANCE;
870 mode1 = ONESIDE_ALLIANCE_TEAM1;
871 mode2 = ONESIDE_ALLIANCE_TEAM2;
873 else
875 side = HORDE;
876 mode1 = ONESIDE_HORDE_TEAM1;
877 mode2 = ONESIDE_HORDE_TEAM2;
880 // create random arena
881 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
882 uint32 arena_num = urand(0,2);
883 BattleGround* bg2 = NULL;
884 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
885 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
886 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
888 sLog.outError("Could not create arena.");
889 return;
892 sLog.outDebug("Battleground: One-faction arena created.");
893 // init stats
894 if(sBattleGroundMgr.isArenaTesting())
896 bg2->SetMaxPlayersPerTeam(1);
897 bg2->SetMaxPlayers(2);
899 else
901 switch(arenatype)
903 case ARENA_TYPE_2v2:
904 bg2->SetMaxPlayersPerTeam(2);
905 bg2->SetMaxPlayers(4);
906 break;
907 case ARENA_TYPE_3v3:
908 bg2->SetMaxPlayersPerTeam(3);
909 bg2->SetMaxPlayers(6);
910 break;
911 case ARENA_TYPE_5v5:
912 bg2->SetMaxPlayersPerTeam(5);
913 bg2->SetMaxPlayers(10);
914 break;
915 default:
916 break;
920 bg2->SetRated(isRated);
922 // assigned team of the other group
923 uint32 other_side;
924 if(side == ALLIANCE)
925 other_side = HORDE;
926 else
927 other_side = ALLIANCE;
929 // start the joining of the bg
930 bg2->SetStatus(STATUS_WAIT_JOIN);
931 bg2->SetQueueId(queue_id);
932 // initialize arena / rating info
933 bg2->SetArenaType(arenatype);
935 std::list<GroupQueueInfo* >::iterator itr;
937 // invite players from the first group as horde players (actually green team)
938 for(itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr)
940 InviteGroupToBG((*itr),bg2,HORDE);
943 // invite players from the second group as ally players (actually gold team)
944 for(itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr)
946 InviteGroupToBG((*itr),bg2,ALLIANCE);
949 if (isRated)
951 std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[mode1].SelectedGroups.begin();
952 std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[mode2].SelectedGroups.begin();
953 (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
954 (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
957 bg2->StartBattleGround();
962 /*********************************************************/
963 /*** BATTLEGROUND QUEUE EVENTS ***/
964 /*********************************************************/
966 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
968 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
970 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
971 if (!plr)
972 return true;
974 // Player can be in another BG queue and must be removed in normal way in any case
975 // // player is already in battleground ... do nothing (battleground queue status is deleted when player is teleported to BG)
976 // if (plr->GetBattleGroundId() > 0)
977 // return true;
979 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
980 if (!bg)
981 return true;
983 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
984 BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
985 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
986 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
988 // 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
989 BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel(bgTypeId)];
990 BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
991 if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
993 WorldPacket data;
994 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0);
995 plr->GetSession()->SendPacket(&data);
998 return true; //event will be deleted
1001 void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
1003 //this should not be called
1004 sLog.outError("Battleground invite event ABORTED!");
1007 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1009 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
1010 if (!plr)
1011 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1012 return true;
1014 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
1015 if (!bg)
1016 return true;
1018 sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
1020 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1021 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1022 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1024 // 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
1025 uint32 queue_id=plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID());
1026 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[queue_id];
1027 BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid);
1028 if (qMapItr != qpMap.end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1030 if (qMapItr->second.GroupInfo->IsRated)
1032 ArenaTeam * at = objmgr.GetArenaTeamById(qMapItr->second.GroupInfo->ArenaTeamId);
1033 if (at)
1035 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(plr->GetGUID()), qMapItr->second.GroupInfo->OpponentsTeamRating);
1036 at->MemberLost(plr, qMapItr->second.GroupInfo->OpponentsTeamRating);
1037 at->SaveToDB();
1040 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
1041 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
1042 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bg->GetTypeID(),bg->GetQueueId());
1043 WorldPacket data;
1044 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0);
1045 plr->GetSession()->SendPacket(&data);
1048 else
1049 sLog.outDebug("Battleground: Player was already removed from queue");
1051 //event will be deleted
1052 return true;
1055 void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
1057 //this should not be called
1058 sLog.outError("Battleground remove event ABORTED!");
1061 /*********************************************************/
1062 /*** BATTLEGROUND MANAGER ***/
1063 /*********************************************************/
1065 BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
1067 m_BattleGrounds.clear();
1068 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1069 m_Testing=false;
1072 BattleGroundMgr::~BattleGroundMgr()
1074 DeleteAlllBattleGrounds();
1077 void BattleGroundMgr::DeleteAlllBattleGrounds()
1079 for(BattleGroundSet::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end();)
1081 BattleGround * bg = itr->second;
1082 m_BattleGrounds.erase(itr++);
1083 delete bg;
1086 // destroy template battlegrounds that listed only in queues (other already terminated)
1087 for(uint32 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId)
1089 // ~BattleGround call unregistring BG from queue
1090 while(!BGFreeSlotQueue[bgTypeId].empty())
1091 delete BGFreeSlotQueue[bgTypeId].front();
1095 // used to update running battlegrounds, and delete finished ones
1096 void BattleGroundMgr::Update(uint32 diff)
1098 BattleGroundSet::iterator itr, next;
1099 for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
1101 next = itr;
1102 ++next;
1103 itr->second->Update(diff);
1104 // use the SetDeleteThis variable
1105 // direct deletion caused crashes
1106 if(itr->second->m_SetDeleteThis)
1108 BattleGround * bg = itr->second;
1109 m_BattleGrounds.erase(itr);
1110 delete bg;
1113 // if rating difference counts, maybe force-update queues
1114 if(sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE))
1116 // it's time to force update
1117 if(m_NextRatingDiscardUpdate < diff)
1119 // forced update for level 70 rated arenas
1120 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA,6,ARENA_TYPE_2v2,true,0);
1121 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA,6,ARENA_TYPE_3v3,true,0);
1122 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA,6,ARENA_TYPE_5v5,true,0);
1123 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1125 else
1126 m_NextRatingDiscardUpdate -= diff;
1128 if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1130 if(m_AutoDistributionTimeChecker < diff)
1132 if(sWorld.GetGameTime() > m_NextAutoDistributionTime)
1134 DistributeArenaPoints();
1135 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1136 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"I64FMTD"'", m_NextAutoDistributionTime);
1138 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1140 else
1141 m_AutoDistributionTimeChecker -= diff;
1145 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted)
1147 // we can be in 3 queues in same time...
1148 if(StatusID == 0)
1150 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
1151 *data << uint32(QueueSlot); // queue id (0...2)
1152 *data << uint64(0);
1153 return;
1156 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
1157 *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1158 // uint64 in client
1159 *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1160 *data << uint32(0); // unknown
1161 // alliance/horde for BG and skirmish/rated for Arenas
1162 *data << uint8(bg->isArena() ? ( israted ? israted : bg->isRated() ) : bg->GetTeamIndexByTeamId(team));
1163 /* *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!!!!
1164 switch(bg->GetTypeID()) // value depends on bg id
1166 case BATTLEGROUND_AV:
1167 *data << uint8(1);
1168 break;
1169 case BATTLEGROUND_WS:
1170 *data << uint8(2);
1171 break;
1172 case BATTLEGROUND_AB:
1173 *data << uint8(3);
1174 break;
1175 case BATTLEGROUND_NA:
1176 *data << uint8(4);
1177 break;
1178 case BATTLEGROUND_BE:
1179 *data << uint8(5);
1180 break;
1181 case BATTLEGROUND_AA:
1182 *data << uint8(6);
1183 break;
1184 case BATTLEGROUND_EY:
1185 *data << uint8(7);
1186 break;
1187 case BATTLEGROUND_RL:
1188 *data << uint8(8);
1189 break;
1190 case BATTLEGROUND_SA:
1191 *data << uint8(9);
1192 break;
1193 case BATTLEGROUND_DS:
1194 *data << uint8(10);
1195 break;
1196 case BATTLEGROUND_RV:
1197 *data << uint8(11);
1198 break;
1199 default: // unknown
1200 *data << uint8(0);
1201 break;
1204 if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1205 *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1206 else
1207 *data << uint32(bg->GetTypeID()); // BG id from DBC
1209 *data << uint16(0x1F90); // unk value 8080
1210 *data << uint32(bg->GetInstanceID()); // instance id
1212 if(bg->isBattleGround())
1213 *data << uint8(bg->GetTeamIndexByTeamId(team)); // team
1214 else
1215 *data << uint8(israted?israted:bg->isRated()); // is rated battle
1217 *data << uint32(StatusID); // status
1218 switch(StatusID)
1220 case STATUS_WAIT_QUEUE: // status_in_queue
1221 *data << uint32(Time1); // average wait time, milliseconds
1222 *data << uint32(Time2); // time in queue, updated every minute?
1223 break;
1224 case STATUS_WAIT_JOIN: // status_invite
1225 *data << uint32(bg->GetMapId()); // map id
1226 *data << uint32(Time1); // time to remove from queue, milliseconds
1227 break;
1228 case STATUS_IN_PROGRESS: // status_in_progress
1229 *data << uint32(bg->GetMapId()); // map id
1230 *data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds
1231 *data << uint32(Time2); // time from bg start, milliseconds
1232 *data << uint8(0x1); // unk sometimes 0x0!
1233 break;
1234 default:
1235 sLog.outError("Unknown BG status!");
1236 break;
1240 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1242 uint8 type = (bg->isArena() ? 1 : 0);
1243 // last check on 3.0.3
1244 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1245 *data << uint8(type); // type (battleground=0/arena=1)
1247 if(type) // arena
1249 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1250 for(int i = 1; i >= 0; --i)
1252 *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
1253 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1254 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1256 for(int i = 1; i >= 0; --i)
1258 uint32 at_id = bg->m_ArenaTeamIds[i];
1259 ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
1260 if(at)
1261 *data << at->GetName();
1262 else
1263 *data << (uint8)0;
1267 if(bg->GetStatus() != STATUS_WAIT_LEAVE)
1269 *data << uint8(0); // bg not ended
1271 else
1273 *data << uint8(1); // bg ended
1274 *data << uint8(bg->GetWinner()); // who win
1277 *data << (int32)(bg->GetPlayerScoresSize());
1279 for(std::map<uint64, BattleGroundScore*>::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1281 *data << (uint64)itr->first;
1282 *data << (int32)itr->second->KillingBlows;
1283 if(type == 0)
1285 *data << (int32)itr->second->HonorableKills;
1286 *data << (int32)itr->second->Deaths;
1287 *data << (int32)(itr->second->BonusHonor);
1289 else
1291 Player *plr = objmgr.GetPlayer(itr->first);
1292 uint32 team = bg->GetPlayerTeam(itr->first);
1293 if(!team && plr)
1294 team = plr->GetTeam();
1295 if( ( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ) )
1296 *data << uint8(1);
1297 else
1298 *data << uint8(0);
1300 *data << (int32)itr->second->DamageDone; // damage done
1301 *data << (int32)itr->second->HealingDone; // healing done
1302 switch(bg->GetTypeID()) // battleground specific things
1304 case BATTLEGROUND_AV:
1305 *data << (uint32)0x00000005; // count of next fields
1306 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1307 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1308 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1309 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1310 *data << (uint32)((BattleGroundAVScore*)itr->second)->MinesCaptured; // MinesCaptured
1311 break;
1312 case BATTLEGROUND_WS:
1313 *data << (uint32)0x00000002; // count of next fields
1314 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1315 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1316 break;
1317 case BATTLEGROUND_AB:
1318 *data << (uint32)0x00000002; // count of next fields
1319 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1320 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1321 break;
1322 case BATTLEGROUND_EY:
1323 *data << (uint32)0x00000001; // count of next fields
1324 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1325 break;
1326 case BATTLEGROUND_NA:
1327 case BATTLEGROUND_BE:
1328 case BATTLEGROUND_AA:
1329 case BATTLEGROUND_RL:
1330 case BATTLEGROUND_SA: // wotlk
1331 case BATTLEGROUND_DS: // wotlk
1332 case BATTLEGROUND_RV: // wotlk
1333 *data << (int32)0; // 0
1334 break;
1335 default:
1336 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1337 *data << (int32)0;
1338 break;
1343 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
1345 /*bgTypeId is:
1346 0 - Your group has joined a battleground queue, but you are not eligible
1347 1 - Your group has joined the queue for AV
1348 2 - Your group has joined the queue for WS
1349 3 - Your group has joined the queue for AB
1350 4 - Your group has joined the queue for NA
1351 5 - Your group has joined the queue for BE Arena
1352 6 - Your group has joined the queue for All Arenas
1353 7 - Your group has joined the queue for EotS*/
1354 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1355 *data << uint32(bgTypeId);
1358 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1360 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1361 *data << uint32(field);
1362 *data << uint32(value);
1365 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1367 data->Initialize(SMSG_PLAY_SOUND, 4);
1368 *data << uint32(soundid);
1371 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, Player *plr)
1373 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1374 *data << uint64(plr->GetGUID());
1377 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1379 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1380 *data << uint64(plr->GetGUID());
1383 void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team)
1385 // set invited player counters:
1386 BattleGround* bg = GetBattleGround(bgInstanceGUID);
1387 if(!bg)
1388 return;
1389 bg->IncreaseInvitedCount(team);
1391 plr->SetInviteForBattleGroundQueueType(BGQueueTypeId(bg->GetTypeID(),bg->GetArenaType()), bgInstanceGUID);
1393 // set the arena teams for rated matches
1394 if(bg->isArena() && bg->isRated())
1396 switch(bg->GetArenaType())
1398 case ARENA_TYPE_2v2:
1399 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));
1400 break;
1401 case ARENA_TYPE_3v3:
1402 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));
1403 break;
1404 case ARENA_TYPE_5v5:
1405 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));
1406 break;
1407 default:
1408 break;
1412 // create invite events:
1413 //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
1414 BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID);
1415 plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME/2));
1416 BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team);
1417 plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
1420 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
1422 return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();
1425 // create a new battleground that will really be used to play
1426 BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId)
1428 // get the template BG
1429 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1430 if(!bg_template)
1432 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1433 return NULL;
1436 BattleGround *bg = NULL;
1438 // create a copy of the BG template
1439 switch(bgTypeId)
1441 case BATTLEGROUND_AV:
1442 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1443 break;
1444 case BATTLEGROUND_WS:
1445 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1446 break;
1447 case BATTLEGROUND_AB:
1448 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1449 break;
1450 case BATTLEGROUND_NA:
1451 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1452 break;
1453 case BATTLEGROUND_BE:
1454 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1455 break;
1456 case BATTLEGROUND_AA:
1457 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1458 break;
1459 case BATTLEGROUND_EY:
1460 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1461 break;
1462 case BATTLEGROUND_RL:
1463 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1464 break;
1465 case BATTLEGROUND_SA:
1466 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1467 break;
1468 case BATTLEGROUND_DS:
1469 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1470 break;
1471 case BATTLEGROUND_RV:
1472 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1473 break;
1474 default:
1475 //error, but it is handled few lines above
1476 return 0;
1479 // generate a new instance id
1480 bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
1482 // reset the new bg (set status to status_wait_queue from status_none)
1483 bg->Reset();
1485 /* will be setup in BG::Update() when the first player is ported in
1486 if(!(bg->SetupBattleGround()))
1488 sLog.outError("BattleGround: CreateNewBattleGround: SetupBattleGround failed for bg %u", bgTypeId);
1489 delete bg;
1490 return 0;
1494 // add BG to free slot queue
1495 bg->AddToBGFreeSlotQueue();
1497 // add bg to update list
1498 AddBattleGround(bg->GetInstanceID(), bg);
1500 return bg;
1503 // used to create the BG templates
1504 uint32 BattleGroundMgr::CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsArena, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO)
1506 // Create the BG
1507 BattleGround *bg = NULL;
1508 switch(bgTypeId)
1510 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1511 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1512 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1513 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1514 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1515 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1516 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1517 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1518 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1519 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1520 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1521 default:bg = new BattleGround; break; // placeholder for non implemented BG
1524 bg->SetMapId(MapID);
1526 bg->Reset();
1528 bg->SetTypeID(bgTypeId);
1529 bg->SetInstanceID(0);
1530 bg->SetArenaorBGType(IsArena);
1531 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1532 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1533 bg->SetMinPlayers(MinPlayersPerTeam * 2);
1534 bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
1535 bg->SetName(BattleGroundName);
1536 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1537 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1538 bg->SetLevelRange(LevelMin, LevelMax);
1540 //add BattleGround instance to FreeSlotQueue (.back() will return the template!)
1541 bg->AddToBGFreeSlotQueue();
1543 // do NOT add to update list, since this is a template battleground!
1545 // return some not-null value, bgTypeId is good enough for me
1546 return bgTypeId;
1549 void BattleGroundMgr::CreateInitialBattleGrounds()
1551 float AStartLoc[4];
1552 float HStartLoc[4];
1553 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1554 BattlemasterListEntry const *bl;
1555 WorldSafeLocsEntry const *start;
1556 bool IsArena;
1558 uint32 count = 0;
1560 // 0 1 2 3 4 5 6 7 8
1561 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1563 if(!result)
1565 barGoLink bar(1);
1567 bar.step();
1569 sLog.outString();
1570 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1571 return;
1574 barGoLink bar(result->GetRowCount());
1578 Field *fields = result->Fetch();
1579 bar.step();
1581 uint32 bgTypeID_ = fields[0].GetUInt32();
1583 // can be overwrite by values from DB
1584 bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
1585 if(!bl)
1587 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
1588 continue;
1591 BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
1593 IsArena = (bl->type == TYPE_ARENA);
1594 MinPlayersPerTeam = fields[1].GetUInt32();
1595 MaxPlayersPerTeam = fields[2].GetUInt32();
1596 MinLvl = fields[3].GetUInt32();
1597 MaxLvl = fields[4].GetUInt32();
1598 //check values from DB
1599 if( MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam )
1601 MaxPlayersPerTeam = bl->maxplayersperteam;
1602 MinPlayersPerTeam = bl->maxplayersperteam / 2;
1604 if( MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl )
1606 MinLvl = bl->minlvl;
1607 MaxLvl = bl->maxlvl;
1610 start1 = fields[5].GetUInt32();
1612 start = sWorldSafeLocsStore.LookupEntry(start1);
1613 if(start)
1615 AStartLoc[0] = start->x;
1616 AStartLoc[1] = start->y;
1617 AStartLoc[2] = start->z;
1618 AStartLoc[3] = fields[6].GetFloat();
1620 else if(bgTypeID == BATTLEGROUND_AA)
1622 AStartLoc[0] = 0;
1623 AStartLoc[1] = 0;
1624 AStartLoc[2] = 0;
1625 AStartLoc[3] = fields[6].GetFloat();
1627 else
1629 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
1630 continue;
1633 start2 = fields[7].GetUInt32();
1635 start = sWorldSafeLocsStore.LookupEntry(start2);
1636 if(start)
1638 HStartLoc[0] = start->x;
1639 HStartLoc[1] = start->y;
1640 HStartLoc[2] = start->z;
1641 HStartLoc[3] = fields[8].GetFloat();
1643 else if(bgTypeID == BATTLEGROUND_AA)
1645 HStartLoc[0] = 0;
1646 HStartLoc[1] = 0;
1647 HStartLoc[2] = 0;
1648 HStartLoc[3] = fields[8].GetFloat();
1650 else
1652 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
1653 continue;
1656 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1657 if(!CreateBattleGround(bgTypeID, IsArena, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, bl->name[sWorld.GetDefaultDbcLocale()], bl->mapid[0], AStartLoc[0], AStartLoc[1], AStartLoc[2], AStartLoc[3], HStartLoc[0], HStartLoc[1], HStartLoc[2], HStartLoc[3]))
1658 continue;
1660 ++count;
1661 } while (result->NextRow());
1663 delete result;
1665 sLog.outString();
1666 sLog.outString( ">> Loaded %u battlegrounds", count );
1669 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1671 if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1673 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1674 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1675 if(!result)
1677 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1678 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1679 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"I64FMTD"')", m_NextAutoDistributionTime);
1681 else
1683 m_NextAutoDistributionTime = (*result)[0].GetUInt64();
1684 delete result;
1686 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1690 void BattleGroundMgr::DistributeArenaPoints()
1692 // used to distribute arena points based on last week's stats
1693 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
1695 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
1697 //temporary structure for storing maximum points to add values for all players
1698 std::map<uint32, uint32> PlayerPoints;
1700 //at first update all points for all team members
1701 for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
1703 if(ArenaTeam * at = team_itr->second)
1705 at->UpdateArenaPointsHelper(PlayerPoints);
1709 //cycle that gives points to all players
1710 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1712 //update to database
1713 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE `guid` = '%u'", plr_itr->second, plr_itr->first);
1714 //add points if player is online
1715 Player* pl = objmgr.GetPlayer(plr_itr->first);
1716 if (pl)
1717 pl->ModifyArenaPoints(plr_itr->second);
1720 PlayerPoints.clear();
1722 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
1724 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
1725 for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
1727 if(ArenaTeam * at = titr->second)
1729 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1730 at->SaveToDB(); // save changes
1731 at->NotifyStatsChanged(); // notify the players of the changes
1735 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
1737 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
1740 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId)
1742 uint32 PlayerLevel = 10;
1744 if(plr)
1745 PlayerLevel = plr->getLevel();
1747 data->Initialize(SMSG_BATTLEFIELD_LIST);
1748 *data << uint64(guid); // battlemaster guid
1749 *data << uint32(bgTypeId); // battleground id
1750 if(bgTypeId == BATTLEGROUND_AA) // arena
1752 *data << uint8(5); // unk
1753 *data << uint32(0); // unk
1755 else // battleground
1757 *data << uint8(0x00); // unk
1759 size_t count_pos = data->wpos();
1760 uint32 count = 0;
1761 *data << uint32(0x00); // number of bg instances
1763 for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
1765 if(itr->second->GetTypeID() == bgTypeId && (PlayerLevel >= itr->second->GetMinLevel()) && (PlayerLevel <= itr->second->GetMaxLevel()))
1767 *data << uint32(itr->second->GetInstanceID());
1768 ++count;
1771 data->put<uint32>( count_pos , count);
1775 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId)
1777 BattleGround *bg = GetBattleGround(instanceId);
1778 if(bg)
1780 uint32 mapid = bg->GetMapId();
1781 float x, y, z, O;
1782 uint32 team = pl->GetBGTeam();
1783 if(team==0)
1784 team = pl->GetTeam();
1785 bg->GetTeamStartLoc(team, x, y, z, O);
1787 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1788 pl->TeleportTo(mapid, x, y, z, O);
1790 else
1792 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1796 void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid)
1798 WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
1799 uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
1800 if(time_ == uint32(-1))
1801 time_ = 0;
1802 data << guid << time_;
1803 pl->GetSession()->SendPacket(&data);
1806 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
1808 return ( bgTypeId == BATTLEGROUND_AA ||
1809 bgTypeId == BATTLEGROUND_BE ||
1810 bgTypeId == BATTLEGROUND_NA ||
1811 bgTypeId == BATTLEGROUND_RL );
1814 BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
1816 switch(bgTypeId)
1818 case BATTLEGROUND_WS:
1819 return BATTLEGROUND_QUEUE_WS;
1820 case BATTLEGROUND_AB:
1821 return BATTLEGROUND_QUEUE_AB;
1822 case BATTLEGROUND_AV:
1823 return BATTLEGROUND_QUEUE_AV;
1824 case BATTLEGROUND_EY:
1825 return BATTLEGROUND_QUEUE_EY;
1826 case BATTLEGROUND_SA:
1827 return BATTLEGROUND_QUEUE_SA;
1828 case BATTLEGROUND_AA:
1829 case BATTLEGROUND_NA:
1830 case BATTLEGROUND_RL:
1831 case BATTLEGROUND_BE:
1832 case BATTLEGROUND_DS:
1833 case BATTLEGROUND_RV:
1834 switch(arenaType)
1836 case ARENA_TYPE_2v2:
1837 return BATTLEGROUND_QUEUE_2v2;
1838 case ARENA_TYPE_3v3:
1839 return BATTLEGROUND_QUEUE_3v3;
1840 case ARENA_TYPE_5v5:
1841 return BATTLEGROUND_QUEUE_5v5;
1842 default:
1843 return BATTLEGROUND_QUEUE_NONE;
1845 default:
1846 return BATTLEGROUND_QUEUE_NONE;
1850 BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId)
1852 switch(bgQueueTypeId)
1854 case BATTLEGROUND_QUEUE_WS:
1855 return BATTLEGROUND_WS;
1856 case BATTLEGROUND_QUEUE_AB:
1857 return BATTLEGROUND_AB;
1858 case BATTLEGROUND_QUEUE_AV:
1859 return BATTLEGROUND_AV;
1860 case BATTLEGROUND_QUEUE_EY:
1861 return BATTLEGROUND_EY;
1862 case BATTLEGROUND_QUEUE_SA:
1863 return BATTLEGROUND_SA;
1864 case BATTLEGROUND_QUEUE_2v2:
1865 case BATTLEGROUND_QUEUE_3v3:
1866 case BATTLEGROUND_QUEUE_5v5:
1867 return BATTLEGROUND_AA;
1868 default:
1869 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
1873 uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId)
1875 switch(bgQueueTypeId)
1877 case BATTLEGROUND_QUEUE_2v2:
1878 return ARENA_TYPE_2v2;
1879 case BATTLEGROUND_QUEUE_3v3:
1880 return ARENA_TYPE_3v3;
1881 case BATTLEGROUND_QUEUE_5v5:
1882 return ARENA_TYPE_5v5;
1883 default:
1884 return 0;
1888 void BattleGroundMgr::ToggleTesting()
1890 m_Testing = !m_Testing;
1891 if(m_Testing)
1892 sWorld.SendWorldText(LANG_DEBUG_BG_ON);
1893 else
1894 sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
1897 void BattleGroundMgr::ToggleArenaTesting()
1899 m_ArenaTesting = !m_ArenaTesting;
1900 if(m_ArenaTesting)
1901 sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
1902 else
1903 sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
1906 uint32 BattleGroundMgr::GetMaxRatingDifference() const
1908 return sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
1911 uint32 BattleGroundMgr::GetRatingDiscardTimer() const
1913 return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1916 uint32 BattleGroundMgr::GetPrematureFinishTime() const
1918 return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
1921 void BattleGroundMgr::LoadBattleMastersEntry()
1923 mBattleMastersMap.clear(); // need for reload case
1925 QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
1927 uint32 count = 0;
1929 if( !result )
1931 barGoLink bar( 1 );
1932 bar.step();
1934 sLog.outString();
1935 sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
1936 return;
1939 barGoLink bar( result->GetRowCount() );
1943 ++count;
1944 bar.step();
1946 Field *fields = result->Fetch();
1948 uint32 entry = fields[0].GetUInt32();
1949 uint32 bgTypeId = fields[1].GetUInt32();
1950 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
1952 sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
1953 continue;
1956 mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
1958 } while( result->NextRow() );
1960 delete result;
1962 sLog.outString();
1963 sLog.outString( ">> Loaded %u battlemaster entries", count );