[7252] Move all world global broadcast string (all arena/bg related) to `mangos_string`.
[getmangos.git] / src / game / BattleGroundMgr.cpp
blob4b31cd0c5ed0e543bf10b362505fff9fe118b581
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()
56 /* for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
58 //m_QueuedPlayers[i].Horde = 0;
59 //m_QueuedPlayers[i].Alliance = 0;
60 //m_QueuedPlayers[i].AverageTime = 0;
61 }*/
64 BattleGroundQueue::~BattleGroundQueue()
66 for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
68 m_QueuedPlayers[i].clear();
69 for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr)
71 delete (*itr);
73 m_QueuedGroups[i].clear();
77 // initialize eligible groups from the given source matching the given specifications
78 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)
80 // clear from prev initialization
81 clear();
82 BattleGroundQueue::QueuedGroupsList::iterator itr, next;
83 // iterate through the source
84 for(itr = source->begin(); itr!= source->end(); itr = next)
86 next = itr;
87 ++next;
88 if( (*itr)->BgTypeId == BgTypeId && // bg type must match
89 (*itr)->ArenaType == ArenaType && // arena type must match
90 (*itr)->IsRated == IsRated && // israted must match
91 (*itr)->IsInvitedToBGInstanceGUID == 0 && // leave out already invited groups
92 (*itr)->Team == side && // match side
93 (*itr)->Players.size() <= MaxPlayers && // the group must fit in the bg
94 ( !excludeTeam || (*itr)->ArenaTeamId != excludeTeam ) && // if excludeTeam is specified, leave out those arena team ids
95 ( !IsRated || (*itr)->Players.size() == MaxPlayers ) && // if rated, then pass only if the player count is exact NEEDS TESTING! (but now this should never happen)
96 ( (*itr)->JoinTime <= DisregardTime // pass if disregard time is greater than join time
97 || (*itr)->ArenaTeamRating == 0 // pass if no rating info
98 || ( (*itr)->ArenaTeamRating >= MinRating // pass if matches the rating range
99 && (*itr)->ArenaTeamRating <= MaxRating ) ) )
101 // the group matches the conditions
102 // insert it in order of groupsize, and join time
103 uint32 size = (*itr)->Players.size();
104 uint32 jointime = (*itr)->JoinTime;
105 bool inserted = false;
107 for(std::list<GroupQueueInfo *>::iterator elig_itr = begin(); elig_itr != end(); ++elig_itr)
109 // if the next one's size is smaller, then insert
110 // also insert if the next one's size is equal, but it joined the queue later
111 if( ((*elig_itr)->Players.size()<size) ||
112 ((*elig_itr)->Players.size() == size && (*elig_itr)->JoinTime > jointime) )
114 insert(elig_itr,(*itr));
115 inserted = true;
116 break;
119 // if not inserted -> this is the smallest group -> push_back
120 if(!inserted)
122 push_back((*itr));
128 // remove group from eligible groups
129 // used when building selection pools
130 void BattleGroundQueue::EligibleGroups::RemoveGroup(GroupQueueInfo * ginfo)
132 for(std::list<GroupQueueInfo *>::iterator itr = begin(); itr != end(); ++itr)
134 if((*itr)==ginfo)
136 erase(itr);
137 return;
142 // selection pool initialization, used to clean up from prev selection
143 void BattleGroundQueue::SelectionPool::Init()
145 SelectedGroups.clear();
146 MaxGroup = 0;
147 PlayerCount = 0;
150 // get the maximal group from the selection pool
151 // used when building the pool, and have to remove the largest
152 GroupQueueInfo * BattleGroundQueue::SelectionPool::GetMaximalGroup()
154 if(SelectedGroups.empty())
156 sLog.outError("Getting max group when selection pool is empty, this should never happen.");
157 MaxGroup = NULL;
158 return 0;
160 // actually select the max group if it's not set
161 if(MaxGroup==0 && !SelectedGroups.empty())
163 uint32 max_size = 0;
164 for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
166 if(max_size<(*itr)->Players.size())
168 MaxGroup =(*itr);
169 max_size = MaxGroup->Players.size();
173 return MaxGroup;
176 // remove group info from selection pool
177 // used when building selection pools and have to remove maximal group
178 void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)
180 // uninitiate max group info if needed
181 if(MaxGroup == ginfo)
182 MaxGroup = 0;
183 // find what to remove
184 for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
186 if((*itr)==ginfo)
188 SelectedGroups.erase(itr);
189 // decrease selected players count
190 PlayerCount -= ginfo->Players.size();
191 return;
196 // add group to selection
197 // used when building selection pools
198 void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)
200 SelectedGroups.push_back(ginfo);
201 // increase selected players count
202 PlayerCount+=ginfo->Players.size();
203 if(!MaxGroup || ginfo->Players.size() > MaxGroup->Players.size())
205 // update max group info if needed
206 MaxGroup = ginfo;
210 // add group to bg queue with the given leader and bg specifications
211 GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating, uint32 arenateamid)
213 uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel();
215 // create new ginfo
216 // cannot use the method like in addplayer, because that could modify an in-queue group's stats
217 // (e.g. leader leaving queue then joining as individual again)
218 GroupQueueInfo* ginfo = new GroupQueueInfo;
219 ginfo->BgTypeId = BgTypeId;
220 ginfo->ArenaType = ArenaType;
221 ginfo->ArenaTeamId = arenateamid;
222 ginfo->IsRated = isRated;
223 ginfo->IsInvitedToBGInstanceGUID = 0; // maybe this should be modifiable by function arguments to enable selection of running instances?
224 ginfo->JoinTime = getMSTime();
225 ginfo->Team = leader->GetTeam();
226 ginfo->ArenaTeamRating = arenaRating;
227 ginfo->OpponentsTeamRating = 0; //initialize it to 0
229 ginfo->Players.clear();
231 m_QueuedGroups[queue_id].push_back(ginfo);
233 // return ginfo, because it is needed to add players to this group info
234 return ginfo;
237 void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
239 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
241 //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
242 PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()];
243 info.InviteTime = 0;
244 info.LastInviteTime = 0;
245 info.LastOnlineTime = getMSTime();
246 info.GroupInfo = ginfo;
248 // add the pinfo to ginfo's list
249 ginfo->Players[plr->GetGUID()] = &info;
252 void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
254 Player *plr = objmgr.GetPlayer(guid);
256 uint32 queue_id = 0;
257 QueuedPlayersMap::iterator itr;
258 GroupQueueInfo * group;
259 QueuedGroupsList::iterator group_itr;
260 bool IsSet = false;
261 if(plr)
263 queue_id = plr->GetBattleGroundQueueIdFromLevel();
265 itr = m_QueuedPlayers[queue_id].find(guid);
266 if(itr != m_QueuedPlayers[queue_id].end())
267 IsSet = true;
270 if(!IsSet)
272 // either player is offline, or he levelled up to another queue category
273 // sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");
274 for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
276 itr = m_QueuedPlayers[i].find(guid);
277 if(itr != m_QueuedPlayers[i].end())
279 queue_id = i;
280 IsSet = true;
281 break;
286 // couldn't find the player in bg queue, return
287 if(!IsSet)
289 sLog.outError("Battleground: couldn't find player to remove.");
290 return;
293 group = itr->second.GroupInfo;
295 for(group_itr=m_QueuedGroups[queue_id].begin(); group_itr != m_QueuedGroups[queue_id].end(); ++group_itr)
297 if(group == (GroupQueueInfo*)(*group_itr))
298 break;
301 // variables are set (what about leveling up when in queue????)
302 // remove player from group
303 // if only player there, remove group
305 // remove player queue info from group queue info
306 std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
308 if(pitr != group->Players.end())
309 group->Players.erase(pitr);
311 // check for iterator correctness
312 if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())
314 // used when player left the queue, NOT used when porting to bg
315 if (decreaseInvitedCount)
317 // if invited to bg, and should decrease invited count, then do it
318 if(group->IsInvitedToBGInstanceGUID)
320 BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID);
321 if (bg)
322 bg->DecreaseInvitedCount(group->Team);
323 if (bg && !bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE))
325 // no more players on battleground, set delete it
326 bg->SetDeleteThis();
329 // update the join queue, maybe now the player's group fits in a queue!
330 // not yet implemented (should store bgTypeId in group queue info?)
332 // remove player queue info
333 m_QueuedPlayers[queue_id].erase(itr);
334 // remove group queue info if needed
336 //if we left BG queue(not porting) OR if arena team left queue for rated match
337 if((decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()))
338 AnnounceWorld(group, guid, false);
340 if(group->Players.empty())
342 m_QueuedGroups[queue_id].erase(group_itr);
343 delete group;
345 // NEEDS TESTING!
346 // group wasn't empty, so it wasn't deleted, and player have left a rated queue -> everyone from the group should leave too
347 // don't remove recursively if already invited to bg!
348 else if(!group->IsInvitedToBGInstanceGUID && decreaseInvitedCount && group->IsRated)
350 // remove next player, this is recursive
351 // first send removal information
352 if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
354 BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
355 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId,group->ArenaType);
356 uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
357 plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
358 WorldPacket data;
359 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr2->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
360 plr2->GetSession()->SendPacket(&data);
362 // then actually delete, this may delete the group as well!
363 RemovePlayer(group->Players.begin()->first,decreaseInvitedCount);
368 void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue)
371 if(ginfo->ArenaType) //if Arena
373 if( sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated)
375 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
376 if(!bg)
377 return;
379 char const* bgName = bg->GetName();
380 if(isAddedToQueue)
381 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
382 else
383 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
386 else //if BG
388 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
390 Player *plr = objmgr.GetPlayer(playerGUID);
391 if(!plr)
392 return;
394 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
395 if(!bg)
396 return;
398 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
399 char const* bgName = bg->GetName();
401 uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id);
402 uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id);
404 // replace hardcoded max level by player max level for nice output
405 if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
406 q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
408 int8 MinPlayers = bg->GetMinPlayersPerTeam();
410 uint8 qHorde = 0;
411 uint8 qAlliance = 0;
413 BattleGroundTypeId bgTypeId = ginfo->BgTypeId;
414 QueuedPlayersMap::iterator itr;
415 for(itr = m_QueuedPlayers[queue_id].begin(); itr!= m_QueuedPlayers[queue_id].end(); ++itr)
417 if(itr->second.GroupInfo->BgTypeId == bgTypeId)
419 switch(itr->second.GroupInfo->Team)
421 case HORDE:
422 qHorde++; break;
423 case ALLIANCE:
424 qAlliance++; break;
425 default:
426 break;
431 // Show queue status to player only (when joining queue)
432 if(sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
434 ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
435 bgName, q_min_level, q_max_level, qAlliance, MinPlayers, qHorde, MinPlayers);
437 // System message
438 else
440 sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
441 bgName, q_min_level, q_max_level, qAlliance, MinPlayers, qHorde, MinPlayers);
447 bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
449 // set side if needed
450 if(side)
451 ginfo->Team = side;
453 if(!ginfo->IsInvitedToBGInstanceGUID)
455 // not yet invited
456 // set invitation
457 ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
458 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
459 // loop through the players
460 for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
462 // set status
463 itr->second->InviteTime = getMSTime();
464 itr->second->LastInviteTime = getMSTime();
466 // get the player
467 Player* plr = objmgr.GetPlayer(itr->first);
468 // if offline, skip him
469 if(!plr)
470 continue;
472 // invite the player
473 sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team);
475 WorldPacket data;
477 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
479 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());
481 // send status packet
482 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, side?side:plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
483 plr->GetSession()->SendPacket(&data);
485 return true;
488 return false;
491 // this function is responsible for the selection of queued groups when trying to create new battlegrounds
492 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)
494 uint32 side;
495 switch(mode)
497 case NORMAL_ALLIANCE:
498 case ONESIDE_ALLIANCE_TEAM1:
499 case ONESIDE_ALLIANCE_TEAM2:
500 side = ALLIANCE;
501 break;
502 case NORMAL_HORDE:
503 case ONESIDE_HORDE_TEAM1:
504 case ONESIDE_HORDE_TEAM2:
505 side = HORDE;
506 break;
507 default:
508 //unknown mode, return false
509 sLog.outDebug("Battleground: unknown selection pool build mode, returning...");
510 return false;
513 // inititate the groups eligible to create the bg
514 m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime, excludeTeam);
515 // init the selected groups (clear)
516 m_SelectionPools[mode].Init();
517 while(!(m_EligibleGroups.empty()))
519 sLog.outDebug("m_EligibleGroups is not empty, continue building selection pool");
520 // in decreasing group size, add groups to join if they fit in the MaxPlayersPerTeam players
521 for(EligibleGroups::iterator itr= m_EligibleGroups.begin(); itr!=m_EligibleGroups.end(); ++itr)
523 // get the maximal not yet checked group
524 GroupQueueInfo * MaxGroup = (*itr);
525 // if it fits in the maxplayer size, add it
526 if( (m_SelectionPools[mode].GetPlayerCount() + MaxGroup->Players.size()) <= MaxPlayers )
528 m_SelectionPools[mode].AddGroup(MaxGroup);
531 if(m_SelectionPools[mode].GetPlayerCount()>=MinPlayers)
533 // the selection pool is set, return
534 sLog.outDebug("pool build succeeded, return true");
535 return true;
537 // if the selection pool's not set, then remove the group with the highest player count, and try again with the rest.
538 GroupQueueInfo * MaxGroup = m_SelectionPools[mode].GetMaximalGroup();
539 m_EligibleGroups.RemoveGroup(MaxGroup);
540 m_SelectionPools[mode].RemoveGroup(MaxGroup);
542 // failed to build a selection pool matching the given values
543 return false;
546 // used to remove the Enter Battle window if the battle has already, but someone still has it
547 // (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event
548 void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
550 uint32 queue_id = bg->GetQueueType();
551 uint32 bgInstanceId = bg->GetInstanceID();
552 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
553 QueuedGroupsList::iterator itr, next;
554 for(itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next)
556 // must do this way, because the groupinfo will be deleted when all playerinfos are removed
557 GroupQueueInfo * ginfo = (*itr);
558 next = itr;
559 ++next;
560 // if group was invited to this bg instance, then remove all references
561 if(ginfo->IsInvitedToBGInstanceGUID == bgInstanceId)
563 // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop
564 uint32 to_remove = ginfo->Players.size();
565 uint32 team = ginfo->Team;
566 for(int i = 0; i < to_remove; ++i)
568 // always remove the first one in the group
569 std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();
570 if(itr2 == ginfo->Players.end())
572 sLog.outError("Empty Players in ginfo, this should never happen!");
573 return;
576 // get the player
577 Player * plr = objmgr.GetPlayer(itr2->first);
578 if(!plr)
580 sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");
581 continue;
584 // get the queueslot
585 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
586 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
588 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
589 // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
590 RemovePlayer(itr2->first, true);
591 // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups
592 // but updateing the queue can't hurt
593 Update(bg->GetTypeID(), bg->GetQueueType());
594 // send info to client
595 WorldPacket data;
596 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0);
597 plr->GetSession()->SendPacket(&data);
605 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
606 it must be called after fully adding the members of a group to ensure group joining
607 should be called after removeplayer functions in some cases
609 void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating)
611 if (queue_id >= MAX_BATTLEGROUND_QUEUES)
613 //this is error, that caused crashes (not in , but now it shouldn't)
614 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");
615 return;
618 //if no players in queue ... do nothing
619 if (m_QueuedGroups[queue_id].empty())
620 return;
622 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype);
624 //battleground with free slot for player should be always the last in this queue
625 BGFreeSlotQueueType::iterator itr, next;
626 for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
628 next = itr;
629 ++next;
630 // battleground is running, so if:
631 // DO NOT allow queue manager to invite new player to running arena
632 if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
634 //we must check both teams
635 BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
636 // and iterator is invalid
638 for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr)
640 // did the group join for this bg type?
641 if((*itr)->BgTypeId != bgTypeId)
642 continue;
643 // if so, check if fits in
644 if(bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size())
646 // if group fits in, invite it
647 InviteGroupToBG((*itr),bg,(*itr)->Team);
651 if (!bg->HasFreeSlots())
653 //remove BG from BGFreeSlotQueue
654 bg->RemoveFromBGFreeSlotQueue();
659 // finished iterating through the bgs with free slots, maybe we need to create a new bg
661 BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
662 if(!bg_template)
664 sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
665 return;
668 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
669 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
670 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
671 if(bg_template->isArena())
673 if(sBattleGroundMgr.isArenaTesting())
675 MaxPlayersPerTeam = 1;
676 MinPlayersPerTeam = 1;
678 else
680 switch(arenatype)
682 case ARENA_TYPE_2v2:
683 MaxPlayersPerTeam = 2;
684 MinPlayersPerTeam = 2;
685 break;
686 case ARENA_TYPE_3v3:
687 MaxPlayersPerTeam = 3;
688 MinPlayersPerTeam = 3;
689 break;
690 case ARENA_TYPE_5v5:
691 MaxPlayersPerTeam = 5;
692 MinPlayersPerTeam = 5;
693 break;
697 // BG case
698 else
700 if(sBattleGroundMgr.isTesting())
702 MinPlayersPerTeam = 1;
706 // found out the minimum and maximum ratings the newly added team should battle against
707 // arenaRating is the rating of the latest joined team
708 uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
709 // if no rating is specified, set maxrating to 0
710 uint32 arenaMaxRating = (arenaRating == 0)? 0 : arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
711 uint32 discardTime = 0;
712 // if max rating difference is set and the time past since server startup is greater than the rating discard time
713 // (after what time the ratings aren't taken into account when making teams) then
714 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
715 // else leave the discard time on 0, this way all ratings will be discarded
716 if(sBattleGroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattleGroundMgr.GetRatingDiscardTimer())
717 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
719 // try to build the selection pools
720 bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
721 if(bAllyOK)
722 sLog.outDebug("Battleground: ally pool succesfully build");
723 else
724 sLog.outDebug("Battleground: ally pool wasn't created");
725 bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
726 if(bHordeOK)
727 sLog.outDebug("Battleground: horde pool succesfully built");
728 else
729 sLog.outDebug("Battleground: horde pool wasn't created");
731 // if selection pools are ready, create the new bg
732 if ((bAllyOK && bHordeOK) || ( sBattleGroundMgr.isTesting() && (bAllyOK || bHordeOK)))
734 BattleGround * bg2 = 0;
735 // special handling for arenas
736 if(bg_template->isArena())
738 // Find a random arena, that can be created
739 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
740 uint32 arena_num = urand(0,2);
741 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
742 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
743 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
745 sLog.outError("Battleground: couldn't create any arena instance!");
746 return;
749 // set the MaxPlayersPerTeam values based on arenatype
750 // setting the min player values isn't needed, since we won't be using that value later on.
751 if(sBattleGroundMgr.isArenaTesting())
753 bg2->SetMaxPlayersPerTeam(1);
754 bg2->SetMaxPlayers(2);
756 else
758 switch(arenatype)
760 case ARENA_TYPE_2v2:
761 bg2->SetMaxPlayersPerTeam(2);
762 bg2->SetMaxPlayers(4);
763 break;
764 case ARENA_TYPE_3v3:
765 bg2->SetMaxPlayersPerTeam(3);
766 bg2->SetMaxPlayers(6);
767 break;
768 case ARENA_TYPE_5v5:
769 bg2->SetMaxPlayersPerTeam(5);
770 bg2->SetMaxPlayers(10);
771 break;
772 default:
773 break;
777 else
779 // create new battleground
780 bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId);
781 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
783 char const* bgName = bg2->GetName();
784 uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id);
785 uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id);
786 if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
787 q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
788 sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level);
792 if(!bg2)
794 sLog.outError("Battleground: couldn't create bg %u",bgTypeId);
795 return;
798 // start the joining of the bg
799 bg2->SetStatus(STATUS_WAIT_JOIN);
800 bg2->SetQueueType(queue_id);
801 // initialize arena / rating info
802 bg2->SetArenaType(arenatype);
803 // set rating
804 bg2->SetRated(isRated);
806 std::list<GroupQueueInfo* >::iterator itr;
808 // invite groups from horde selection pool
809 for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr)
811 InviteGroupToBG((*itr),bg2,HORDE);
814 // invite groups from ally selection pools
815 for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)
817 InviteGroupToBG((*itr),bg2,ALLIANCE);
820 if (isRated)
822 std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin();
823 std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin();
824 (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
825 sLog.outDebug("setting oposite teamrating for team %u to %u", (*itr_alliance)->ArenaTeamId, (*itr_alliance)->OpponentsTeamRating);
826 (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
827 sLog.outDebug("setting oposite teamrating for team %u to %u", (*itr_horde)->ArenaTeamId, (*itr_horde)->OpponentsTeamRating);
830 // start the battleground
831 bg2->StartBattleGround();
834 // there weren't enough players for a "normal" match
835 // if arena, enable horde versus horde or alliance versus alliance teams here
837 else if(bg_template->isArena())
839 bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false;
840 bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false;
841 bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
842 if(bOneSideHordeTeam1)
844 // one team has been selected, find out if other can be selected too
845 std::list<GroupQueueInfo* >::iterator itr;
846 // temporarily change the team side to enable building the next pool excluding the already selected groups
847 for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
848 (*itr)->Team=ALLIANCE;
850 bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime, (*(m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
852 // change back the team to horde
853 for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
854 (*itr)->Team=HORDE;
856 if(!bOneSideHordeTeam2)
857 bOneSideHordeTeam1 = false;
859 if(!bOneSideHordeTeam1)
861 // check for one sided ally
862 bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
863 if(bOneSideAllyTeam1)
865 // one team has been selected, find out if other can be selected too
866 std::list<GroupQueueInfo* >::iterator itr;
867 // temporarily change the team side to enable building the next pool excluding the already selected groups
868 for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
869 (*itr)->Team=HORDE;
871 bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime,(*(m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
873 // change back the team to ally
874 for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
875 (*itr)->Team=ALLIANCE;
878 if(!bOneSideAllyTeam2)
879 bOneSideAllyTeam1 = false;
881 // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!
882 if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) ||
883 (bOneSideAllyTeam1 && bOneSideAllyTeam2) )
885 // which side has enough players?
886 uint32 side = 0;
887 SelectionPoolBuildMode mode1, mode2;
888 // find out what pools are we using
889 if(bOneSideAllyTeam1 && bOneSideAllyTeam2)
891 side = ALLIANCE;
892 mode1 = ONESIDE_ALLIANCE_TEAM1;
893 mode2 = ONESIDE_ALLIANCE_TEAM2;
895 else
897 side = HORDE;
898 mode1 = ONESIDE_HORDE_TEAM1;
899 mode2 = ONESIDE_HORDE_TEAM2;
902 // create random arena
903 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
904 uint32 arena_num = urand(0,2);
905 BattleGround* bg2 = NULL;
906 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
907 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
908 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
910 sLog.outError("Could not create arena.");
911 return;
914 sLog.outDebug("Battleground: One-faction arena created.");
915 // init stats
916 if(sBattleGroundMgr.isArenaTesting())
918 bg2->SetMaxPlayersPerTeam(1);
919 bg2->SetMaxPlayers(2);
921 else
923 switch(arenatype)
925 case ARENA_TYPE_2v2:
926 bg2->SetMaxPlayersPerTeam(2);
927 bg2->SetMaxPlayers(4);
928 break;
929 case ARENA_TYPE_3v3:
930 bg2->SetMaxPlayersPerTeam(3);
931 bg2->SetMaxPlayers(6);
932 break;
933 case ARENA_TYPE_5v5:
934 bg2->SetMaxPlayersPerTeam(5);
935 bg2->SetMaxPlayers(10);
936 break;
937 default:
938 break;
942 bg2->SetRated(isRated);
944 // assigned team of the other group
945 uint32 other_side;
946 if(side == ALLIANCE)
947 other_side = HORDE;
948 else
949 other_side = ALLIANCE;
951 // start the joining of the bg
952 bg2->SetStatus(STATUS_WAIT_JOIN);
953 bg2->SetQueueType(queue_id);
954 // initialize arena / rating info
955 bg2->SetArenaType(arenatype);
957 std::list<GroupQueueInfo* >::iterator itr;
959 // invite players from the first group as horde players (actually green team)
960 for(itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr)
962 InviteGroupToBG((*itr),bg2,HORDE);
965 // invite players from the second group as ally players (actually gold team)
966 for(itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr)
968 InviteGroupToBG((*itr),bg2,ALLIANCE);
971 if (isRated)
973 std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[mode1].SelectedGroups.begin();
974 std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[mode2].SelectedGroups.begin();
975 (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
976 (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
979 bg2->StartBattleGround();
984 /*********************************************************/
985 /*** BATTLEGROUND QUEUE EVENTS ***/
986 /*********************************************************/
988 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
990 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
992 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
993 if (!plr)
994 return true;
996 // Player can be in another BG queue and must be removed in normal way in any case
997 // // player is already in battleground ... do nothing (battleground queue status is deleted when player is teleported to BG)
998 // if (plr->GetBattleGroundId() > 0)
999 // return true;
1001 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
1002 if (!bg)
1003 return true;
1005 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1006 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1007 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1009 // 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
1010 BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
1011 BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
1012 if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1014 WorldPacket data;
1015 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0);
1016 plr->GetSession()->SendPacket(&data);
1019 return true; //event will be deleted
1022 void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
1024 //this should not be called
1025 sLog.outError("Battleground invite event ABORTED!");
1028 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1030 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
1031 if (!plr)
1032 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1033 return true;
1035 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
1036 if (!bg)
1037 return true;
1039 sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
1041 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1042 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1043 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1045 // 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
1046 BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid);
1047 if (qMapItr != sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1049 if (qMapItr->second.GroupInfo->IsRated)
1051 ArenaTeam * at = objmgr.GetArenaTeamById(qMapItr->second.GroupInfo->ArenaTeamId);
1052 if (at)
1054 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(plr->GetGUID()), qMapItr->second.GroupInfo->OpponentsTeamRating);
1055 at->MemberLost(plr, qMapItr->second.GroupInfo->OpponentsTeamRating);
1056 at->SaveToDB();
1059 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
1060 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
1061 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bg->GetTypeID(),bg->GetQueueType());
1062 WorldPacket data;
1063 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0);
1064 plr->GetSession()->SendPacket(&data);
1067 else
1068 sLog.outDebug("Battleground: Player was already removed from queue");
1070 //event will be deleted
1071 return true;
1074 void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
1076 //this should not be called
1077 sLog.outError("Battleground remove event ABORTED!");
1080 /*********************************************************/
1081 /*** BATTLEGROUND MANAGER ***/
1082 /*********************************************************/
1084 BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
1086 m_BattleGrounds.clear();
1087 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1088 m_Testing=false;
1091 BattleGroundMgr::~BattleGroundMgr()
1093 BattleGroundSet::iterator itr, next;
1094 for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
1096 next = itr;
1097 ++next;
1098 BattleGround * bg = itr->second;
1099 m_BattleGrounds.erase(itr);
1100 delete bg;
1102 m_BattleGrounds.clear();
1105 // used to update running battlegrounds, and delete finished ones
1106 void BattleGroundMgr::Update(uint32 diff)
1108 BattleGroundSet::iterator itr, next;
1109 for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
1111 next = itr;
1112 ++next;
1113 itr->second->Update(diff);
1114 // use the SetDeleteThis variable
1115 // direct deletion caused crashes
1116 if(itr->second->m_SetDeleteThis)
1118 BattleGround * bg = itr->second;
1119 m_BattleGrounds.erase(itr);
1120 delete bg;
1123 // if rating difference counts, maybe force-update queues
1124 if(sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE))
1126 // it's time to force update
1127 if(m_NextRatingDiscardUpdate < diff)
1129 // forced update for level 70 rated arenas
1130 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA,6,ARENA_TYPE_2v2,true,0);
1131 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA,6,ARENA_TYPE_3v3,true,0);
1132 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA,6,ARENA_TYPE_5v5,true,0);
1133 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1135 else
1136 m_NextRatingDiscardUpdate -= diff;
1138 if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1140 if(m_AutoDistributionTimeChecker < diff)
1142 if(sWorld.GetGameTime() > m_NextAutoDistributionTime)
1144 DistributeArenaPoints();
1145 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1146 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"I64FMTD"'", m_NextAutoDistributionTime);
1148 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1150 else
1151 m_AutoDistributionTimeChecker -= diff;
1155 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted)
1157 // we can be in 3 queues in same time...
1158 if(StatusID == 0)
1160 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
1161 *data << uint32(QueueSlot); // queue id (0...2)
1162 *data << uint64(0);
1163 return;
1166 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
1167 *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1168 // uint64 in client
1169 *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1170 *data << uint32(0); // unknown
1171 // alliance/horde for BG and skirmish/rated for Arenas
1172 *data << uint8(bg->isArena() ? ( israted ? israted : bg->isRated() ) : bg->GetTeamIndexByTeamId(team));
1173 /* *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!!!!
1174 switch(bg->GetTypeID()) // value depends on bg id
1176 case BATTLEGROUND_AV:
1177 *data << uint8(1);
1178 break;
1179 case BATTLEGROUND_WS:
1180 *data << uint8(2);
1181 break;
1182 case BATTLEGROUND_AB:
1183 *data << uint8(3);
1184 break;
1185 case BATTLEGROUND_NA:
1186 *data << uint8(4);
1187 break;
1188 case BATTLEGROUND_BE:
1189 *data << uint8(5);
1190 break;
1191 case BATTLEGROUND_AA:
1192 *data << uint8(6);
1193 break;
1194 case BATTLEGROUND_EY:
1195 *data << uint8(7);
1196 break;
1197 case BATTLEGROUND_RL:
1198 *data << uint8(8);
1199 break;
1200 case BATTLEGROUND_SA:
1201 *data << uint8(9);
1202 break;
1203 case BATTLEGROUND_DS:
1204 *data << uint8(10);
1205 break;
1206 case BATTLEGROUND_RV:
1207 *data << uint8(11);
1208 break;
1209 default: // unknown
1210 *data << uint8(0);
1211 break;
1214 if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1215 *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1216 else
1217 *data << uint32(bg->GetTypeID()); // BG id from DBC
1219 *data << uint16(0x1F90); // unk value 8080
1220 *data << uint32(bg->GetInstanceID()); // instance id
1222 if(bg->isBattleGround())
1223 *data << uint8(bg->GetTeamIndexByTeamId(team)); // team
1224 else
1225 *data << uint8(israted?israted:bg->isRated()); // is rated battle
1227 *data << uint32(StatusID); // status
1228 switch(StatusID)
1230 case STATUS_WAIT_QUEUE: // status_in_queue
1231 *data << uint32(Time1); // average wait time, milliseconds
1232 *data << uint32(Time2); // time in queue, updated every minute?
1233 break;
1234 case STATUS_WAIT_JOIN: // status_invite
1235 *data << uint32(bg->GetMapId()); // map id
1236 *data << uint32(Time1); // time to remove from queue, milliseconds
1237 break;
1238 case STATUS_IN_PROGRESS: // status_in_progress
1239 *data << uint32(bg->GetMapId()); // map id
1240 *data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds
1241 *data << uint32(Time2); // time from bg start, milliseconds
1242 *data << uint8(0x1); // unk sometimes 0x0!
1243 break;
1244 default:
1245 sLog.outError("Unknown BG status!");
1246 break;
1250 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1252 uint8 type = (bg->isArena() ? 1 : 0);
1253 // last check on 3.0.3
1254 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1255 *data << uint8(type); // type (battleground=0/arena=1)
1257 if(type) // arena
1259 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1260 for(int i = 1; i >= 0; --i)
1262 *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
1263 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1264 *data << uint32(0); // unknown - new in 3.0.3
1265 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1267 for(int i = 1; i >= 0; --i)
1269 uint32 at_id = bg->m_ArenaTeamIds[i];
1270 ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
1271 if(at)
1272 *data << at->GetName();
1273 else//*/
1274 *data << (uint8)0;
1278 if(bg->GetStatus() != STATUS_WAIT_LEAVE)
1280 *data << uint8(0); // bg not ended
1282 else
1284 *data << uint8(1); // bg ended
1285 *data << uint8(bg->GetWinner()); // who win
1288 *data << (int32)(bg->GetPlayerScoresSize());
1290 for(std::map<uint64, BattleGroundScore*>::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1292 *data << (uint64)itr->first;
1293 *data << (int32)itr->second->KillingBlows;
1294 if(type == 0)
1296 *data << (int32)itr->second->HonorableKills;
1297 *data << (int32)itr->second->Deaths;
1298 *data << (int32)(itr->second->BonusHonor);
1300 else
1302 Player *plr = objmgr.GetPlayer(itr->first);
1303 uint32 team = bg->GetPlayerTeam(itr->first);
1304 if(!team && plr)
1305 team = plr->GetTeam();
1306 if( ( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ) )
1307 *data << uint8(1);
1308 else
1309 *data << uint8(0);
1311 *data << (int32)itr->second->DamageDone; // damage done
1312 *data << (int32)itr->second->HealingDone; // healing done
1313 switch(bg->GetTypeID()) // battleground specific things
1315 case BATTLEGROUND_AV:
1316 *data << (uint32)0x00000005; // count of next fields
1317 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1318 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1319 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1320 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1321 *data << (uint32)((BattleGroundAVScore*)itr->second)->MinesCaptured; // MinesCaptured
1322 break;
1323 case BATTLEGROUND_WS:
1324 *data << (uint32)0x00000002; // count of next fields
1325 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1326 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1327 break;
1328 case BATTLEGROUND_AB:
1329 *data << (uint32)0x00000002; // count of next fields
1330 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1331 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1332 break;
1333 case BATTLEGROUND_EY:
1334 *data << (uint32)0x00000001; // count of next fields
1335 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1336 break;
1337 case BATTLEGROUND_NA:
1338 case BATTLEGROUND_BE:
1339 case BATTLEGROUND_AA:
1340 case BATTLEGROUND_RL:
1341 case BATTLEGROUND_SA: // wotlk
1342 case BATTLEGROUND_DS: // wotlk
1343 case BATTLEGROUND_RV: // wotlk
1344 *data << (int32)0; // 0
1345 break;
1346 default:
1347 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1348 *data << (int32)0;
1349 break;
1354 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
1356 /*bgTypeId is:
1357 0 - Your group has joined a battleground queue, but you are not eligible
1358 1 - Your group has joined the queue for AV
1359 2 - Your group has joined the queue for WS
1360 3 - Your group has joined the queue for AB
1361 4 - Your group has joined the queue for NA
1362 5 - Your group has joined the queue for BE Arena
1363 6 - Your group has joined the queue for All Arenas
1364 7 - Your group has joined the queue for EotS*/
1365 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1366 *data << uint32(bgTypeId);
1369 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1371 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1372 *data << uint32(field);
1373 *data << uint32(value);
1376 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1378 data->Initialize(SMSG_PLAY_SOUND, 4);
1379 *data << uint32(soundid);
1382 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, Player *plr)
1384 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1385 *data << uint64(plr->GetGUID());
1388 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1390 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1391 *data << uint64(plr->GetGUID());
1394 void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team)
1396 // set invited player counters:
1397 BattleGround* bg = GetBattleGround(bgInstanceGUID);
1398 if(!bg)
1399 return;
1400 bg->IncreaseInvitedCount(team);
1402 plr->SetInviteForBattleGroundQueueType(BGQueueTypeId(bg->GetTypeID(),bg->GetArenaType()), bgInstanceGUID);
1404 // set the arena teams for rated matches
1405 if(bg->isArena() && bg->isRated())
1407 switch(bg->GetArenaType())
1409 case ARENA_TYPE_2v2:
1410 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));
1411 break;
1412 case ARENA_TYPE_3v3:
1413 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));
1414 break;
1415 case ARENA_TYPE_5v5:
1416 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));
1417 break;
1418 default:
1419 break;
1423 // create invite events:
1424 //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
1425 BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID);
1426 plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME/2));
1427 BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team);
1428 plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
1431 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
1433 return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();
1436 // create a new battleground that will really be used to play
1437 BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId)
1439 // get the template BG
1440 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1441 if(!bg_template)
1443 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1444 return NULL;
1447 BattleGround *bg = NULL;
1449 // create a copy of the BG template
1450 switch(bgTypeId)
1452 case BATTLEGROUND_AV:
1453 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1454 break;
1455 case BATTLEGROUND_WS:
1456 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1457 break;
1458 case BATTLEGROUND_AB:
1459 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1460 break;
1461 case BATTLEGROUND_NA:
1462 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1463 break;
1464 case BATTLEGROUND_BE:
1465 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1466 break;
1467 case BATTLEGROUND_AA:
1468 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1469 break;
1470 case BATTLEGROUND_EY:
1471 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1472 break;
1473 case BATTLEGROUND_RL:
1474 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1475 break;
1476 case BATTLEGROUND_SA:
1477 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1478 break;
1479 case BATTLEGROUND_DS:
1480 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1481 break;
1482 case BATTLEGROUND_RV:
1483 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1484 break;
1485 default:
1486 //bg = new BattleGround;
1487 return 0;
1488 break; // placeholder for non implemented BG
1491 // generate a new instance id
1492 bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
1494 // reset the new bg (set status to status_wait_queue from status_none)
1495 bg->Reset();
1497 /* will be setup in BG::Update() when the first player is ported in
1498 if(!(bg->SetupBattleGround()))
1500 sLog.outError("BattleGround: CreateNewBattleGround: SetupBattleGround failed for bg %u", bgTypeId);
1501 delete bg;
1502 return 0;
1506 // add BG to free slot queue
1507 bg->AddToBGFreeSlotQueue();
1509 // add bg to update list
1510 AddBattleGround(bg->GetInstanceID(), bg);
1512 return bg;
1515 // used to create the BG templates
1516 uint32 BattleGroundMgr::CreateBattleGround(BattleGroundTypeId 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)
1518 // Create the BG
1519 BattleGround *bg = NULL;
1521 switch(bgTypeId)
1523 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1524 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1525 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1526 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1527 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1528 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1529 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1530 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1531 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1532 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1533 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1534 default:bg = new BattleGround; break; // placeholder for non implemented BG
1537 bg->SetMapId(MapID);
1539 bg->Reset();
1541 BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId);
1542 //in previous method is checked if exists entry in sBattlemasterListStore, so no check needed
1543 if (bl)
1545 bg->SetArenaorBGType(bl->type == TYPE_ARENA);
1548 bg->SetTypeID(bgTypeId);
1549 bg->SetInstanceID(0); // template bg, instance id is 0
1550 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1551 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1552 bg->SetMinPlayers(MinPlayersPerTeam*2);
1553 bg->SetMaxPlayers(MaxPlayersPerTeam*2);
1554 bg->SetName(BattleGroundName);
1555 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1556 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1557 bg->SetLevelRange(LevelMin, LevelMax);
1559 //add BattleGround instance to FreeSlotQueue (.back() will return the template!)
1560 bg->AddToBGFreeSlotQueue();
1562 // do NOT add to update list, since this is a template battleground!
1564 // return some not-null value, bgTypeId is good enough for me
1565 return bgTypeId;
1568 void BattleGroundMgr::CreateInitialBattleGrounds()
1570 float AStartLoc[4];
1571 float HStartLoc[4];
1572 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1573 BattlemasterListEntry const *bl;
1574 WorldSafeLocsEntry const *start;
1576 uint32 count = 0;
1578 // 0 1 2 3 4 5 6 7 8
1579 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1581 if(!result)
1583 barGoLink bar(1);
1585 bar.step();
1587 sLog.outString();
1588 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1589 return;
1592 barGoLink bar(result->GetRowCount());
1596 Field *fields = result->Fetch();
1597 bar.step();
1599 uint32 bgTypeID_ = fields[0].GetUInt32();
1601 // can be overwrite by values from DB
1602 bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
1603 if(!bl)
1605 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.",bgTypeID_);
1606 continue;
1609 BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
1611 MaxPlayersPerTeam = bl->maxplayersperteam;
1612 MinPlayersPerTeam = bl->maxplayersperteam/2;
1613 MinLvl = bl->minlvl;
1614 MaxLvl = bl->maxlvl;
1616 if(fields[1].GetUInt32())
1617 MinPlayersPerTeam = fields[1].GetUInt32();
1619 if(fields[2].GetUInt32())
1620 MaxPlayersPerTeam = fields[2].GetUInt32();
1622 if(fields[3].GetUInt32())
1623 MinLvl = fields[3].GetUInt32();
1625 if(fields[4].GetUInt32())
1626 MaxLvl = fields[4].GetUInt32();
1628 start1 = fields[5].GetUInt32();
1630 start = sWorldSafeLocsStore.LookupEntry(start1);
1631 if(start)
1633 AStartLoc[0] = start->x;
1634 AStartLoc[1] = start->y;
1635 AStartLoc[2] = start->z;
1636 AStartLoc[3] = fields[6].GetFloat();
1638 else if(bgTypeID == BATTLEGROUND_AA)
1640 AStartLoc[0] = 0;
1641 AStartLoc[1] = 0;
1642 AStartLoc[2] = 0;
1643 AStartLoc[3] = fields[6].GetFloat();
1645 else
1647 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.",bgTypeID,start1);
1648 continue;
1651 start2 = fields[7].GetUInt32();
1653 start = sWorldSafeLocsStore.LookupEntry(start2);
1654 if(start)
1656 HStartLoc[0] = start->x;
1657 HStartLoc[1] = start->y;
1658 HStartLoc[2] = start->z;
1659 HStartLoc[3] = fields[8].GetFloat();
1661 else if(bgTypeID == BATTLEGROUND_AA)
1663 HStartLoc[0] = 0;
1664 HStartLoc[1] = 0;
1665 HStartLoc[2] = 0;
1666 HStartLoc[3] = fields[8].GetFloat();
1668 else
1670 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.",bgTypeID,start2);
1671 continue;
1674 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1675 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]))
1676 continue;
1678 ++count;
1679 } while (result->NextRow());
1681 delete result;
1683 sLog.outString();
1684 sLog.outString( ">> Loaded %u battlegrounds", count );
1687 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1689 if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1691 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1692 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1693 if(!result)
1695 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1696 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1697 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"I64FMTD"')", m_NextAutoDistributionTime);
1699 else
1701 m_NextAutoDistributionTime = (*result)[0].GetUInt64();
1702 delete result;
1704 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1708 void BattleGroundMgr::DistributeArenaPoints()
1710 // used to distribute arena points based on last week's stats
1711 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
1713 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
1715 //temporary structure for storing maximum points to add values for all players
1716 std::map<uint32, uint32> PlayerPoints;
1718 //at first update all points for all team members
1719 for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
1721 if(ArenaTeam * at = team_itr->second)
1723 at->UpdateArenaPointsHelper(PlayerPoints);
1727 //cycle that gives points to all players
1728 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1730 //update to database
1731 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE `guid` = '%u'", plr_itr->second, plr_itr->first);
1732 //add points if player is online
1733 Player* pl = objmgr.GetPlayer(plr_itr->first);
1734 if (pl)
1735 pl->ModifyArenaPoints(plr_itr->second);
1738 PlayerPoints.clear();
1740 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
1742 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
1743 for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
1745 if(ArenaTeam * at = titr->second)
1747 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1748 at->SaveToDB(); // save changes
1749 at->NotifyStatsChanged(); // notify the players of the changes
1753 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
1755 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
1758 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId)
1760 uint32 PlayerLevel = 10;
1762 if(plr)
1763 PlayerLevel = plr->getLevel();
1765 data->Initialize(SMSG_BATTLEFIELD_LIST);
1766 *data << uint64(guid); // battlemaster guid
1767 *data << uint32(bgTypeId); // battleground id
1768 if(bgTypeId == BATTLEGROUND_AA) // arena
1770 *data << uint8(5); // unk
1771 *data << uint32(0); // unk
1773 else // battleground
1775 *data << uint8(0x00); // unk
1777 size_t count_pos = data->wpos();
1778 uint32 count = 0;
1779 *data << uint32(0x00); // number of bg instances
1781 for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
1783 if(itr->second->GetTypeID() == bgTypeId && (PlayerLevel >= itr->second->GetMinLevel()) && (PlayerLevel <= itr->second->GetMaxLevel()))
1785 *data << uint32(itr->second->GetInstanceID());
1786 ++count;
1789 data->put<uint32>( count_pos , count);
1793 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId)
1795 BattleGround *bg = GetBattleGround(instanceId);
1796 if(bg)
1798 uint32 mapid = bg->GetMapId();
1799 float x, y, z, O;
1800 uint32 team = pl->GetBGTeam();
1801 if(team==0)
1802 team = pl->GetTeam();
1803 bg->GetTeamStartLoc(team, x, y, z, O);
1805 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1806 pl->TeleportTo(mapid, x, y, z, O);
1808 else
1810 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1814 void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid)
1816 WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
1817 uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
1818 if(time_ == uint32(-1))
1819 time_ = 0;
1820 data << guid << time_;
1821 pl->GetSession()->SendPacket(&data);
1824 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
1826 return ( bgTypeId == BATTLEGROUND_AA ||
1827 bgTypeId == BATTLEGROUND_BE ||
1828 bgTypeId == BATTLEGROUND_NA ||
1829 bgTypeId == BATTLEGROUND_RL );
1832 uint32 BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
1834 switch(bgTypeId)
1836 case BATTLEGROUND_WS:
1837 return BATTLEGROUND_QUEUE_WS;
1838 case BATTLEGROUND_AB:
1839 return BATTLEGROUND_QUEUE_AB;
1840 case BATTLEGROUND_AV:
1841 return BATTLEGROUND_QUEUE_AV;
1842 case BATTLEGROUND_EY:
1843 return BATTLEGROUND_QUEUE_EY;
1844 case BATTLEGROUND_SA:
1845 return BATTLEGROUND_QUEUE_SA;
1846 case BATTLEGROUND_AA:
1847 case BATTLEGROUND_NA:
1848 case BATTLEGROUND_RL:
1849 case BATTLEGROUND_BE:
1850 case BATTLEGROUND_DS:
1851 case BATTLEGROUND_RV:
1852 switch(arenaType)
1854 case ARENA_TYPE_2v2:
1855 return BATTLEGROUND_QUEUE_2v2;
1856 case ARENA_TYPE_3v3:
1857 return BATTLEGROUND_QUEUE_3v3;
1858 case ARENA_TYPE_5v5:
1859 return BATTLEGROUND_QUEUE_5v5;
1860 default:
1861 return 0;
1863 default:
1864 return 0;
1868 BattleGroundTypeId BattleGroundMgr::BGTemplateId(uint32 bgQueueTypeId)
1870 switch(bgQueueTypeId)
1872 case BATTLEGROUND_QUEUE_WS:
1873 return BATTLEGROUND_WS;
1874 case BATTLEGROUND_QUEUE_AB:
1875 return BATTLEGROUND_AB;
1876 case BATTLEGROUND_QUEUE_AV:
1877 return BATTLEGROUND_AV;
1878 case BATTLEGROUND_QUEUE_EY:
1879 return BATTLEGROUND_EY;
1880 case BATTLEGROUND_QUEUE_SA:
1881 return BATTLEGROUND_SA;
1882 case BATTLEGROUND_QUEUE_2v2:
1883 case BATTLEGROUND_QUEUE_3v3:
1884 case BATTLEGROUND_QUEUE_5v5:
1885 return BATTLEGROUND_AA;
1886 default:
1887 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
1891 uint8 BattleGroundMgr::BGArenaType(uint32 bgQueueTypeId)
1893 switch(bgQueueTypeId)
1895 case BATTLEGROUND_QUEUE_2v2:
1896 return ARENA_TYPE_2v2;
1897 case BATTLEGROUND_QUEUE_3v3:
1898 return ARENA_TYPE_3v3;
1899 case BATTLEGROUND_QUEUE_5v5:
1900 return ARENA_TYPE_5v5;
1901 default:
1902 return 0;
1906 void BattleGroundMgr::ToggleTesting()
1908 m_Testing = !m_Testing;
1909 if(m_Testing)
1910 sWorld.SendWorldText(LANG_DEBUG_BG_ON);
1911 else
1912 sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
1915 void BattleGroundMgr::ToggleArenaTesting()
1917 m_ArenaTesting = !m_ArenaTesting;
1918 if(m_ArenaTesting)
1919 sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
1920 else
1921 sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
1924 uint32 BattleGroundMgr::GetMaxRatingDifference() const
1926 return sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
1929 uint32 BattleGroundMgr::GetRatingDiscardTimer() const
1931 return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1934 uint32 BattleGroundMgr::GetPrematureFinishTime() const
1936 return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
1939 void BattleGroundMgr::LoadBattleMastersEntry()
1941 mBattleMastersMap.clear(); // need for reload case
1943 QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
1945 uint32 count = 0;
1947 if( !result )
1949 barGoLink bar( 1 );
1950 bar.step();
1952 sLog.outString();
1953 sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
1954 return;
1957 barGoLink bar( result->GetRowCount() );
1961 ++count;
1962 bar.step();
1964 Field *fields = result->Fetch();
1966 uint32 entry = fields[0].GetUInt32();
1967 uint32 bgTypeId = fields[1].GetUInt32();
1968 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
1970 sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
1971 continue;
1974 mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
1976 } while( result->NextRow() );
1978 delete result;
1980 sLog.outString();
1981 sLog.outString( ">> Loaded %u battlemaster entries", count );