[7110] Make some methods in BattleGroundMgr static.
[getmangos.git] / src / game / BattleGroundMgr.cpp
blobc21af527c107aa0fee06bddb89a41afa348e1e13
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Player.h"
21 #include "BattleGroundMgr.h"
22 #include "BattleGroundAV.h"
23 #include "BattleGroundAB.h"
24 #include "BattleGroundEY.h"
25 #include "BattleGroundWS.h"
26 #include "BattleGroundNA.h"
27 #include "BattleGroundBE.h"
28 #include "BattleGroundAA.h"
29 #include "BattleGroundRL.h"
30 #include "BattleGroundSA.h"
31 #include "BattleGroundDS.h"
32 #include "BattleGroundRV.h"
33 #include "SharedDefines.h"
34 #include "Policies/SingletonImp.h"
35 #include "MapManager.h"
36 #include "Map.h"
37 #include "MapInstanced.h"
38 #include "ObjectMgr.h"
39 #include "ProgressBar.h"
40 #include "Chat.h"
41 #include "ArenaTeam.h"
43 INSTANTIATE_SINGLETON_1( BattleGroundMgr );
45 /*********************************************************/
46 /*** BATTLEGROUND QUEUE SYSTEM ***/
47 /*********************************************************/
49 BattleGroundQueue::BattleGroundQueue()
51 //queues are empty, we don't have to call clear()
52 /* for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
54 //m_QueuedPlayers[i].Horde = 0;
55 //m_QueuedPlayers[i].Alliance = 0;
56 //m_QueuedPlayers[i].AverageTime = 0;
57 }*/
60 BattleGroundQueue::~BattleGroundQueue()
62 for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
64 m_QueuedPlayers[i].clear();
65 for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr)
67 delete (*itr);
69 m_QueuedGroups[i].clear();
73 // initialize eligible groups from the given source matching the given specifications
74 void BattleGroundQueue::EligibleGroups::Init(BattleGroundQueue::QueuedGroupsList *source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType, bool IsRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam)
76 // clear from prev initialization
77 clear();
78 BattleGroundQueue::QueuedGroupsList::iterator itr, next;
79 // iterate through the source
80 for(itr = source->begin(); itr!= source->end(); itr = next)
82 next = itr;
83 ++next;
84 if( (*itr)->BgTypeId == BgTypeId && // bg type must match
85 (*itr)->ArenaType == ArenaType && // arena type must match
86 (*itr)->IsRated == IsRated && // israted must match
87 (*itr)->IsInvitedToBGInstanceGUID == 0 && // leave out already invited groups
88 (*itr)->Team == side && // match side
89 (*itr)->Players.size() <= MaxPlayers && // the group must fit in the bg
90 ( !excludeTeam || (*itr)->ArenaTeamId != excludeTeam ) && // if excludeTeam is specified, leave out those arena team ids
91 ( !IsRated || (*itr)->Players.size() == MaxPlayers ) && // if rated, then pass only if the player count is exact NEEDS TESTING! (but now this should never happen)
92 ( (*itr)->JoinTime <= DisregardTime // pass if disregard time is greater than join time
93 || (*itr)->ArenaTeamRating == 0 // pass if no rating info
94 || ( (*itr)->ArenaTeamRating >= MinRating // pass if matches the rating range
95 && (*itr)->ArenaTeamRating <= MaxRating ) ) )
97 // the group matches the conditions
98 // insert it in order of groupsize, and join time
99 uint32 size = (*itr)->Players.size();
100 uint32 jointime = (*itr)->JoinTime;
101 bool inserted = false;
103 for(std::list<GroupQueueInfo *>::iterator elig_itr = begin(); elig_itr != end(); ++elig_itr)
105 // if the next one's size is smaller, then insert
106 // also insert if the next one's size is equal, but it joined the queue later
107 if( ((*elig_itr)->Players.size()<size) ||
108 ((*elig_itr)->Players.size() == size && (*elig_itr)->JoinTime > jointime) )
110 insert(elig_itr,(*itr));
111 inserted = true;
112 break;
115 // if not inserted -> this is the smallest group -> push_back
116 if(!inserted)
118 push_back((*itr));
124 // remove group from eligible groups
125 // used when building selection pools
126 void BattleGroundQueue::EligibleGroups::RemoveGroup(GroupQueueInfo * ginfo)
128 for(std::list<GroupQueueInfo *>::iterator itr = begin(); itr != end(); ++itr)
130 if((*itr)==ginfo)
132 erase(itr);
133 return;
138 // selection pool initialization, used to clean up from prev selection
139 void BattleGroundQueue::SelectionPool::Init()
141 SelectedGroups.clear();
142 MaxGroup = 0;
143 PlayerCount = 0;
146 // get the maximal group from the selection pool
147 // used when building the pool, and have to remove the largest
148 GroupQueueInfo * BattleGroundQueue::SelectionPool::GetMaximalGroup()
150 if(SelectedGroups.empty())
152 sLog.outError("Getting max group when selection pool is empty, this should never happen.");
153 MaxGroup = NULL;
154 return 0;
156 // actually select the max group if it's not set
157 if(MaxGroup==0 && !SelectedGroups.empty())
159 uint32 max_size = 0;
160 for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
162 if(max_size<(*itr)->Players.size())
164 MaxGroup =(*itr);
165 max_size = MaxGroup->Players.size();
169 return MaxGroup;
172 // remove group info from selection pool
173 // used when building selection pools and have to remove maximal group
174 void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)
176 // uninitiate max group info if needed
177 if(MaxGroup == ginfo)
178 MaxGroup = 0;
179 // find what to remove
180 for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
182 if((*itr)==ginfo)
184 SelectedGroups.erase(itr);
185 // decrease selected players count
186 PlayerCount -= ginfo->Players.size();
187 return;
192 // add group to selection
193 // used when building selection pools
194 void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)
196 SelectedGroups.push_back(ginfo);
197 // increase selected players count
198 PlayerCount+=ginfo->Players.size();
199 if(!MaxGroup || ginfo->Players.size() > MaxGroup->Players.size())
201 // update max group info if needed
202 MaxGroup = ginfo;
206 // add group to bg queue with the given leader and bg specifications
207 GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating, uint32 arenateamid)
209 uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel();
211 // create new ginfo
212 // cannot use the method like in addplayer, because that could modify an in-queue group's stats
213 // (e.g. leader leaving queue then joining as individual again)
214 GroupQueueInfo* ginfo = new GroupQueueInfo;
215 ginfo->BgTypeId = BgTypeId;
216 ginfo->ArenaType = ArenaType;
217 ginfo->ArenaTeamId = arenateamid;
218 ginfo->IsRated = isRated;
219 ginfo->IsInvitedToBGInstanceGUID = 0; // maybe this should be modifiable by function arguments to enable selection of running instances?
220 ginfo->JoinTime = getMSTime();
221 ginfo->Team = leader->GetTeam();
222 ginfo->ArenaTeamRating = arenaRating;
223 ginfo->OpponentsTeamRating = 0; //initialize it to 0
225 ginfo->Players.clear();
227 m_QueuedGroups[queue_id].push_back(ginfo);
229 // return ginfo, because it is needed to add players to this group info
230 return ginfo;
233 void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
235 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
237 //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
238 PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()];
239 info.InviteTime = 0;
240 info.LastInviteTime = 0;
241 info.LastOnlineTime = getMSTime();
242 info.GroupInfo = ginfo;
244 // add the pinfo to ginfo's list
245 ginfo->Players[plr->GetGUID()] = &info;
248 void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
250 Player *plr = objmgr.GetPlayer(guid);
252 uint32 queue_id = 0;
253 QueuedPlayersMap::iterator itr;
254 GroupQueueInfo * group;
255 QueuedGroupsList::iterator group_itr;
256 bool IsSet = false;
257 if(plr)
259 queue_id = plr->GetBattleGroundQueueIdFromLevel();
261 itr = m_QueuedPlayers[queue_id].find(guid);
262 if(itr != m_QueuedPlayers[queue_id].end())
263 IsSet = true;
266 if(!IsSet)
268 // either player is offline, or he levelled up to another queue category
269 // sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");
270 for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
272 itr = m_QueuedPlayers[i].find(guid);
273 if(itr != m_QueuedPlayers[i].end())
275 queue_id = i;
276 IsSet = true;
277 break;
282 // couldn't find the player in bg queue, return
283 if(!IsSet)
285 sLog.outError("Battleground: couldn't find player to remove.");
286 return;
289 group = itr->second.GroupInfo;
291 for(group_itr=m_QueuedGroups[queue_id].begin(); group_itr != m_QueuedGroups[queue_id].end(); ++group_itr)
293 if(group == (GroupQueueInfo*)(*group_itr))
294 break;
297 // variables are set (what about leveling up when in queue????)
298 // remove player from group
299 // if only player there, remove group
301 // remove player queue info from group queue info
302 std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
304 if(pitr != group->Players.end())
305 group->Players.erase(pitr);
307 // check for iterator correctness
308 if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())
310 // used when player left the queue, NOT used when porting to bg
311 if (decreaseInvitedCount)
313 // if invited to bg, and should decrease invited count, then do it
314 if(group->IsInvitedToBGInstanceGUID)
316 BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID);
317 if (bg)
318 bg->DecreaseInvitedCount(group->Team);
319 if (bg && !bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE))
321 // no more players on battleground, set delete it
322 bg->SetDeleteThis();
325 // update the join queue, maybe now the player's group fits in a queue!
326 // not yet implemented (should store bgTypeId in group queue info?)
328 // remove player queue info
329 m_QueuedPlayers[queue_id].erase(itr);
330 // remove group queue info if needed
332 //if we left BG queue(not porting) OR if arena team left queue for rated match
333 if((decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()))
334 AnnounceWorld(group, guid, false);
336 if(group->Players.empty())
338 m_QueuedGroups[queue_id].erase(group_itr);
339 delete group;
341 // NEEDS TESTING!
342 // group wasn't empty, so it wasn't deleted, and player have left a rated queue -> everyone from the group should leave too
343 // don't remove recursively if already invited to bg!
344 else if(!group->IsInvitedToBGInstanceGUID && decreaseInvitedCount && group->IsRated)
346 // remove next player, this is recursive
347 // first send removal information
348 if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
350 BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
351 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId,group->ArenaType);
352 uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
353 plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
354 WorldPacket data;
355 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr2->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
356 plr2->GetSession()->SendPacket(&data);
358 // then actually delete, this may delete the group as well!
359 RemovePlayer(group->Players.begin()->first,decreaseInvitedCount);
364 void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue)
367 if(ginfo->ArenaType) //if Arena
369 if( sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated)
371 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
372 if(!bg)
373 return;
375 char const* bgName = bg->GetName();
376 if(isAddedToQueue)
377 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
378 else
379 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
382 else //if BG
384 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
386 Player *plr = objmgr.GetPlayer(playerGUID);
387 if(!plr)
388 return;
390 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
391 if(!bg)
392 return;
394 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
395 char const* bgName = bg->GetName();
397 uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id);
398 uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id);
400 // replace hardcoded max level by player max level for nice output
401 if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
402 q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
404 int8 MinPlayers = bg->GetMinPlayersPerTeam();
406 uint8 qHorde = 0;
407 uint8 qAlliance = 0;
409 uint32 bgTypeId = ginfo->BgTypeId;
410 QueuedPlayersMap::iterator itr;
411 for(itr = m_QueuedPlayers[queue_id].begin(); itr!= m_QueuedPlayers[queue_id].end(); ++itr)
413 if(itr->second.GroupInfo->BgTypeId == bgTypeId)
415 switch(itr->second.GroupInfo->Team)
417 case HORDE:
418 qHorde++; break;
419 case ALLIANCE:
420 qAlliance++; break;
421 default:
422 break;
427 // Show queue status to player only (when joining queue)
428 if(sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
430 ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
431 bgName, q_min_level, q_max_level, qAlliance, MinPlayers, qHorde, MinPlayers);
433 // System message
434 else
436 sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
437 bgName, q_min_level, q_max_level, qAlliance, MinPlayers, qHorde, MinPlayers);
443 bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
445 // set side if needed
446 if(side)
447 ginfo->Team = side;
449 if(!ginfo->IsInvitedToBGInstanceGUID)
451 // not yet invited
452 // set invitation
453 ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
454 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
455 // loop through the players
456 for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
458 // set status
459 itr->second->InviteTime = getMSTime();
460 itr->second->LastInviteTime = getMSTime();
462 // get the player
463 Player* plr = objmgr.GetPlayer(itr->first);
464 // if offline, skip him
465 if(!plr)
466 continue;
468 // invite the player
469 sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team);
471 WorldPacket data;
473 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
475 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());
477 // send status packet
478 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, side?side:plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
479 plr->GetSession()->SendPacket(&data);
481 return true;
484 return false;
487 // this function is responsible for the selection of queued groups when trying to create new battlegrounds
488 bool BattleGroundQueue::BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType, bool isRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam)
490 uint32 side;
491 switch(mode)
493 case NORMAL_ALLIANCE:
494 case ONESIDE_ALLIANCE_TEAM1:
495 case ONESIDE_ALLIANCE_TEAM2:
496 side = ALLIANCE;
497 break;
498 case NORMAL_HORDE:
499 case ONESIDE_HORDE_TEAM1:
500 case ONESIDE_HORDE_TEAM2:
501 side = HORDE;
502 break;
503 default:
504 //unknown mode, return false
505 sLog.outDebug("Battleground: unknown selection pool build mode, returning...");
506 return false;
507 break;
510 // inititate the groups eligible to create the bg
511 m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime, excludeTeam);
512 // init the selected groups (clear)
513 m_SelectionPools[mode].Init();
514 while(!(m_EligibleGroups.empty()))
516 sLog.outDebug("m_EligibleGroups is not empty, continue building selection pool");
517 // in decreasing group size, add groups to join if they fit in the MaxPlayersPerTeam players
518 for(EligibleGroups::iterator itr= m_EligibleGroups.begin(); itr!=m_EligibleGroups.end(); ++itr)
520 // get the maximal not yet checked group
521 GroupQueueInfo * MaxGroup = (*itr);
522 // if it fits in the maxplayer size, add it
523 if( (m_SelectionPools[mode].GetPlayerCount() + MaxGroup->Players.size()) <= MaxPlayers )
525 m_SelectionPools[mode].AddGroup(MaxGroup);
528 if(m_SelectionPools[mode].GetPlayerCount()>=MinPlayers)
530 // the selection pool is set, return
531 sLog.outDebug("pool build succeeded, return true");
532 return true;
534 // if the selection pool's not set, then remove the group with the highest player count, and try again with the rest.
535 GroupQueueInfo * MaxGroup = m_SelectionPools[mode].GetMaximalGroup();
536 m_EligibleGroups.RemoveGroup(MaxGroup);
537 m_SelectionPools[mode].RemoveGroup(MaxGroup);
539 // failed to build a selection pool matching the given values
540 return false;
543 // used to remove the Enter Battle window if the battle has already, but someone still has it
544 // (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event
545 void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
547 uint32 queue_id = bg->GetQueueType();
548 uint32 bgInstanceId = bg->GetInstanceID();
549 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
550 QueuedGroupsList::iterator itr, next;
551 for(itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next)
553 // must do this way, because the groupinfo will be deleted when all playerinfos are removed
554 GroupQueueInfo * ginfo = (*itr);
555 next = itr;
556 ++next;
557 // if group was invited to this bg instance, then remove all references
558 if(ginfo->IsInvitedToBGInstanceGUID == bgInstanceId)
560 // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop
561 uint32 to_remove = ginfo->Players.size();
562 uint32 team = ginfo->Team;
563 for(int i = 0; i < to_remove; ++i)
565 // always remove the first one in the group
566 std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();
567 if(itr2 == ginfo->Players.end())
569 sLog.outError("Empty Players in ginfo, this should never happen!");
570 return;
573 // get the player
574 Player * plr = objmgr.GetPlayer(itr2->first);
575 if(!plr)
577 sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");
578 continue;
581 // get the queueslot
582 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
583 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
585 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
586 // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
587 RemovePlayer(itr2->first, true);
588 // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups
589 // but updateing the queue can't hurt
590 Update(bgQueueTypeId, bg->GetQueueType());
591 // send info to client
592 WorldPacket data;
593 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0);
594 plr->GetSession()->SendPacket(&data);
602 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
603 it must be called after fully adding the members of a group to ensure group joining
604 should be called after removeplayer functions in some cases
606 void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating)
608 if (queue_id >= MAX_BATTLEGROUND_QUEUES)
610 //this is error, that caused crashes (not in , but now it shouldn't)
611 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");
612 return;
615 //if no players in queue ... do nothing
616 if (m_QueuedGroups[queue_id].empty())
617 return;
619 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype);
621 //battleground with free slot for player should be always the last in this queue
622 BGFreeSlotQueueType::iterator itr, next;
623 for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
625 next = itr;
626 ++next;
627 // battleground is running, so if:
628 // DO NOT allow queue manager to invite new player to running arena
629 if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
631 //we must check both teams
632 BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
633 // and iterator is invalid
635 for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr)
637 // did the group join for this bg type?
638 if((*itr)->BgTypeId != bgTypeId)
639 continue;
640 // if so, check if fits in
641 if(bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size())
643 // if group fits in, invite it
644 InviteGroupToBG((*itr),bg,(*itr)->Team);
648 if (!bg->HasFreeSlots())
650 //remove BG from BGFreeSlotQueue
651 bg->RemoveFromBGFreeSlotQueue();
656 // finished iterating through the bgs with free slots, maybe we need to create a new bg
658 BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
659 if(!bg_template)
661 sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
662 return;
665 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
666 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
667 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
668 if(bg_template->isArena())
670 if(sBattleGroundMgr.isArenaTesting())
672 MaxPlayersPerTeam = 1;
673 MinPlayersPerTeam = 1;
675 else
677 switch(arenatype)
679 case ARENA_TYPE_2v2:
680 MaxPlayersPerTeam = 2;
681 MinPlayersPerTeam = 2;
682 break;
683 case ARENA_TYPE_3v3:
684 MaxPlayersPerTeam = 3;
685 MinPlayersPerTeam = 3;
686 break;
687 case ARENA_TYPE_5v5:
688 MaxPlayersPerTeam = 5;
689 MinPlayersPerTeam = 5;
690 break;
695 // found out the minimum and maximum ratings the newly added team should battle against
696 // arenaRating is the rating of the latest joined team
697 uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
698 // if no rating is specified, set maxrating to 0
699 uint32 arenaMaxRating = (arenaRating == 0)? 0 : arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
700 uint32 discardTime = 0;
701 // if max rating difference is set and the time past since server startup is greater than the rating discard time
702 // (after what time the ratings aren't taken into account when making teams) then
703 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
704 // else leave the discard time on 0, this way all ratings will be discarded
705 if(sBattleGroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattleGroundMgr.GetRatingDiscardTimer())
706 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
708 // try to build the selection pools
709 bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
710 if(bAllyOK)
711 sLog.outDebug("Battleground: ally pool succesfully build");
712 else
713 sLog.outDebug("Battleground: ally pool wasn't created");
714 bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
715 if(bHordeOK)
716 sLog.outDebug("Battleground: horde pool succesfully built");
717 else
718 sLog.outDebug("Battleground: horde pool wasn't created");
720 // if selection pools are ready, create the new bg
721 if (bAllyOK && bHordeOK)
723 BattleGround * bg2 = 0;
724 // special handling for arenas
725 if(bg_template->isArena())
727 // Find a random arena, that can be created
728 uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
729 uint32 arena_num = urand(0,2);
730 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
731 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
732 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
734 sLog.outError("Battleground: couldn't create any arena instance!");
735 return;
738 // set the MaxPlayersPerTeam values based on arenatype
739 // setting the min player values isn't needed, since we won't be using that value later on.
740 if(sBattleGroundMgr.isArenaTesting())
742 bg2->SetMaxPlayersPerTeam(1);
743 bg2->SetMaxPlayers(2);
745 else
747 switch(arenatype)
749 case ARENA_TYPE_2v2:
750 bg2->SetMaxPlayersPerTeam(2);
751 bg2->SetMaxPlayers(4);
752 break;
753 case ARENA_TYPE_3v3:
754 bg2->SetMaxPlayersPerTeam(3);
755 bg2->SetMaxPlayers(6);
756 break;
757 case ARENA_TYPE_5v5:
758 bg2->SetMaxPlayersPerTeam(5);
759 bg2->SetMaxPlayers(10);
760 break;
761 default:
762 break;
766 else
768 // create new battleground
769 bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId);
770 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
772 char const* bgName = bg2->GetName();
773 uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id);
774 uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id);
775 if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
776 q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
777 sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level);
781 if(!bg2)
783 sLog.outError("Battleground: couldn't create bg %u",bgTypeId);
784 return;
787 // start the joining of the bg
788 bg2->SetStatus(STATUS_WAIT_JOIN);
789 bg2->SetQueueType(queue_id);
790 // initialize arena / rating info
791 bg2->SetArenaType(arenatype);
792 // set rating
793 bg2->SetRated(isRated);
795 std::list<GroupQueueInfo* >::iterator itr;
797 // invite groups from horde selection pool
798 for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr)
800 InviteGroupToBG((*itr),bg2,HORDE);
803 // invite groups from ally selection pools
804 for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)
806 InviteGroupToBG((*itr),bg2,ALLIANCE);
809 if (isRated)
811 std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin();
812 std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin();
813 (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
814 sLog.outDebug("setting oposite teamrating for team %u to %u", (*itr_alliance)->ArenaTeamId, (*itr_alliance)->OpponentsTeamRating);
815 (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
816 sLog.outDebug("setting oposite teamrating for team %u to %u", (*itr_horde)->ArenaTeamId, (*itr_horde)->OpponentsTeamRating);
819 // start the battleground
820 bg2->StartBattleGround();
823 // there weren't enough players for a "normal" match
824 // if arena, enable horde versus horde or alliance versus alliance teams here
826 else if(bg_template->isArena())
828 bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false;
829 bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false;
830 bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
831 if(bOneSideHordeTeam1)
833 // one team has been selected, find out if other can be selected too
834 std::list<GroupQueueInfo* >::iterator itr;
835 // temporarily change the team side to enable building the next pool excluding the already selected groups
836 for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
837 (*itr)->Team=ALLIANCE;
839 bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime, (*(m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
841 // change back the team to horde
842 for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
843 (*itr)->Team=HORDE;
845 if(!bOneSideHordeTeam2)
846 bOneSideHordeTeam1 = false;
848 if(!bOneSideHordeTeam1)
850 // check for one sided ally
851 bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
852 if(bOneSideAllyTeam1)
854 // one team has been selected, find out if other can be selected too
855 std::list<GroupQueueInfo* >::iterator itr;
856 // temporarily change the team side to enable building the next pool excluding the already selected groups
857 for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
858 (*itr)->Team=HORDE;
860 bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime,(*(m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
862 // change back the team to ally
863 for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
864 (*itr)->Team=ALLIANCE;
867 if(!bOneSideAllyTeam2)
868 bOneSideAllyTeam1 = false;
870 // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!
871 if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) ||
872 (bOneSideAllyTeam1 && bOneSideAllyTeam2) )
874 // which side has enough players?
875 uint32 side = 0;
876 SelectionPoolBuildMode mode1, mode2;
877 // find out what pools are we using
878 if(bOneSideAllyTeam1 && bOneSideAllyTeam2)
880 side = ALLIANCE;
881 mode1 = ONESIDE_ALLIANCE_TEAM1;
882 mode2 = ONESIDE_ALLIANCE_TEAM2;
884 else
886 side = HORDE;
887 mode1 = ONESIDE_HORDE_TEAM1;
888 mode2 = ONESIDE_HORDE_TEAM2;
891 // create random arena
892 uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
893 uint32 arena_num = urand(0,2);
894 BattleGround* bg2 = NULL;
895 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
896 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
897 !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
899 sLog.outError("Could not create arena.");
900 return;
903 sLog.outDebug("Battleground: One-faction arena created.");
904 // init stats
905 if(sBattleGroundMgr.isArenaTesting())
907 bg2->SetMaxPlayersPerTeam(1);
908 bg2->SetMaxPlayers(2);
910 else
912 switch(arenatype)
914 case ARENA_TYPE_2v2:
915 bg2->SetMaxPlayersPerTeam(2);
916 bg2->SetMaxPlayers(4);
917 break;
918 case ARENA_TYPE_3v3:
919 bg2->SetMaxPlayersPerTeam(3);
920 bg2->SetMaxPlayers(6);
921 break;
922 case ARENA_TYPE_5v5:
923 bg2->SetMaxPlayersPerTeam(5);
924 bg2->SetMaxPlayers(10);
925 break;
926 default:
927 break;
931 bg2->SetRated(isRated);
933 // assigned team of the other group
934 uint32 other_side;
935 if(side == ALLIANCE)
936 other_side = HORDE;
937 else
938 other_side = ALLIANCE;
940 // start the joining of the bg
941 bg2->SetStatus(STATUS_WAIT_JOIN);
942 bg2->SetQueueType(queue_id);
943 // initialize arena / rating info
944 bg2->SetArenaType(arenatype);
946 std::list<GroupQueueInfo* >::iterator itr;
948 // invite players from the first group as horde players (actually green team)
949 for(itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr)
951 InviteGroupToBG((*itr),bg2,HORDE);
954 // invite players from the second group as ally players (actually gold team)
955 for(itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr)
957 InviteGroupToBG((*itr),bg2,ALLIANCE);
960 if (isRated)
962 std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[mode1].SelectedGroups.begin();
963 std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[mode2].SelectedGroups.begin();
964 (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
965 (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
968 bg2->StartBattleGround();
973 /*********************************************************/
974 /*** BATTLEGROUND QUEUE EVENTS ***/
975 /*********************************************************/
977 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
979 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
981 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
982 if (!plr)
983 return true;
985 // Player can be in another BG queue and must be removed in normal way in any case
986 // // player is already in battleground ... do nothing (battleground queue status is deleted when player is teleported to BG)
987 // if (plr->GetBattleGroundId() > 0)
988 // return true;
990 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
991 if (!bg)
992 return true;
994 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());
995 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
997 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
998 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
999 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1001 // 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
1002 BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
1003 BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
1004 if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1006 WorldPacket data;
1007 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0);
1008 plr->GetSession()->SendPacket(&data);
1012 return true; //event will be deleted
1015 void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
1017 //this should not be called
1018 sLog.outError("Battleground invite event ABORTED!");
1021 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1023 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
1024 if (!plr)
1025 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1026 return true;
1028 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
1029 if (!bg)
1030 return true;
1032 sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
1034 uint32 bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1035 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1036 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1038 // 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
1039 BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid);
1040 if (qMapItr != sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1042 if (qMapItr->second.GroupInfo->IsRated)
1044 ArenaTeam * at = objmgr.GetArenaTeamById(qMapItr->second.GroupInfo->ArenaTeamId);
1045 if (at)
1047 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(plr->GetGUID()), qMapItr->second.GroupInfo->OpponentsTeamRating);
1048 at->MemberLost(plr, qMapItr->second.GroupInfo->OpponentsTeamRating);
1049 at->SaveToDB();
1052 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
1053 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
1054 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgQueueTypeId, bg->GetQueueType());
1055 WorldPacket data;
1056 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0);
1057 plr->GetSession()->SendPacket(&data);
1060 else
1061 sLog.outDebug("Battleground: Player was already removed from queue");
1063 //event will be deleted
1064 return true;
1067 void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
1069 //this should not be called
1070 sLog.outError("Battleground remove event ABORTED!");
1073 /*********************************************************/
1074 /*** BATTLEGROUND MANAGER ***/
1075 /*********************************************************/
1077 BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
1079 m_BattleGrounds.clear();
1080 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1083 BattleGroundMgr::~BattleGroundMgr()
1085 BattleGroundSet::iterator itr, next;
1086 for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
1088 next = itr;
1089 ++next;
1090 BattleGround * bg = itr->second;
1091 m_BattleGrounds.erase(itr);
1092 delete bg;
1094 m_BattleGrounds.clear();
1097 // used to update running battlegrounds, and delete finished ones
1098 void BattleGroundMgr::Update(time_t diff)
1100 BattleGroundSet::iterator itr, next;
1101 for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
1103 next = itr;
1104 ++next;
1105 itr->second->Update(diff);
1106 // use the SetDeleteThis variable
1107 // direct deletion caused crashes
1108 if(itr->second->m_SetDeleteThis)
1110 BattleGround * bg = itr->second;
1111 m_BattleGrounds.erase(itr);
1112 delete bg;
1115 // if rating difference counts, maybe force-update queues
1116 if(sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE))
1118 // it's time to force update
1119 if(m_NextRatingDiscardUpdate < diff)
1121 // forced update for level 70 rated arenas
1122 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA,6,ARENA_TYPE_2v2,true,0);
1123 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA,6,ARENA_TYPE_3v3,true,0);
1124 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA,6,ARENA_TYPE_5v5,true,0);
1125 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1127 else
1128 m_NextRatingDiscardUpdate -= diff;
1130 if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1132 if(m_AutoDistributionTimeChecker < diff)
1134 if(sWorld.GetGameTime() > m_NextAutoDistributionTime)
1136 DistributeArenaPoints();
1137 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1138 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"I64FMTD"'", m_NextAutoDistributionTime);
1140 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1142 else
1143 m_AutoDistributionTimeChecker -= diff;
1147 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted)
1149 // we can be in 3 queues in same time...
1150 if(StatusID == 0)
1152 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
1153 *data << uint32(QueueSlot); // queue id (0...2)
1154 *data << uint64(0);
1155 return;
1158 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
1159 *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1160 // uint64 in client
1161 *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1162 *data << uint32(0); // unknown
1163 // alliance/horde for BG and skirmish/rated for Arenas
1164 *data << uint8(bg->isArena() ? ( israted ? israted : bg->isRated() ) : bg->GetTeamIndexByTeamId(team));
1165 /* *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!!!!
1166 switch(bg->GetTypeID()) // value depends on bg id
1168 case BATTLEGROUND_AV:
1169 *data << uint8(1);
1170 break;
1171 case BATTLEGROUND_WS:
1172 *data << uint8(2);
1173 break;
1174 case BATTLEGROUND_AB:
1175 *data << uint8(3);
1176 break;
1177 case BATTLEGROUND_NA:
1178 *data << uint8(4);
1179 break;
1180 case BATTLEGROUND_BE:
1181 *data << uint8(5);
1182 break;
1183 case BATTLEGROUND_AA:
1184 *data << uint8(6);
1185 break;
1186 case BATTLEGROUND_EY:
1187 *data << uint8(7);
1188 break;
1189 case BATTLEGROUND_RL:
1190 *data << uint8(8);
1191 break;
1192 case BATTLEGROUND_SA:
1193 *data << uint8(9);
1194 break;
1195 case BATTLEGROUND_DS:
1196 *data << uint8(10);
1197 break;
1198 case BATTLEGROUND_RV:
1199 *data << uint8(11);
1200 break;
1201 default: // unknown
1202 *data << uint8(0);
1203 break;
1206 if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1207 *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1208 else
1209 *data << uint32(bg->GetTypeID()); // BG id from DBC
1211 *data << uint16(0x1F90); // unk value 8080
1212 *data << uint32(bg->GetInstanceID()); // instance id
1214 if(bg->isBattleGround())
1215 *data << uint8(bg->GetTeamIndexByTeamId(team)); // team
1216 else
1217 *data << uint8(israted?israted:bg->isRated()); // is rated battle
1219 *data << uint32(StatusID); // status
1220 switch(StatusID)
1222 case STATUS_WAIT_QUEUE: // status_in_queue
1223 *data << uint32(Time1); // average wait time, milliseconds
1224 *data << uint32(Time2); // time in queue, updated every minute?
1225 break;
1226 case STATUS_WAIT_JOIN: // status_invite
1227 *data << uint32(bg->GetMapId()); // map id
1228 *data << uint32(Time1); // time to remove from queue, milliseconds
1229 break;
1230 case STATUS_IN_PROGRESS: // status_in_progress
1231 *data << uint32(bg->GetMapId()); // map id
1232 *data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds
1233 *data << uint32(Time2); // time from bg start, milliseconds
1234 *data << uint8(0x1); // unk sometimes 0x0!
1235 break;
1236 default:
1237 sLog.outError("Unknown BG status!");
1238 break;
1242 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1244 uint8 type = (bg->isArena() ? 1 : 0);
1245 // last check on 2.4.1
1246 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1247 *data << uint8(type); // seems to be type (battleground=0/arena=1)
1249 if(type) // arena
1251 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1252 for(int i = 1; i >= 0; --i)
1254 *data << uint32(3000-bg->m_ArenaTeamRatingChanges[i]); // rating change: showed value - 3000
1255 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1256 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1258 for(int i = 1; i >= 0; --i)
1260 uint32 at_id = bg->m_ArenaTeamIds[i];
1261 ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
1262 if(at)
1263 *data << at->GetName();
1264 else//*/
1265 *data << (uint8)0;
1269 if(bg->GetWinner() == 2)
1271 *data << uint8(0); // bg in progress
1273 else
1275 *data << uint8(1); // bg ended
1276 *data << uint8(bg->GetWinner()); // who win
1279 *data << (int32)(bg->GetPlayerScoresSize());
1281 for(std::map<uint64, BattleGroundScore*>::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1283 *data << (uint64)itr->first;
1284 *data << (int32)itr->second->KillingBlows;
1285 Player *plr = objmgr.GetPlayer(itr->first);
1286 uint32 team = bg->GetPlayerTeam(itr->first);
1287 if(!team && plr) team = plr->GetTeam();
1288 if(type == 0)
1290 *data << (int32)itr->second->HonorableKills;
1291 *data << (int32)itr->second->Deaths;
1292 *data << (int32)(itr->second->BonusHonor);
1294 else
1296 // that part probably wrong
1297 if(plr)
1299 if(team == HORDE)
1300 *data << uint8(0);
1301 else if(team == ALLIANCE)
1303 *data << uint8(1);
1305 else
1306 *data << uint8(0);
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, uint32 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(uint32 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(uint32 bgTypeId)
1439 BattleGround *bg = NULL;
1441 // get the template BG
1442 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1444 if(!bg_template)
1446 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1447 return 0;
1450 // create a copy of the BG template
1451 switch(bgTypeId)
1453 case BATTLEGROUND_AV:
1454 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1455 break;
1456 case BATTLEGROUND_WS:
1457 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1458 break;
1459 case BATTLEGROUND_AB:
1460 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1461 break;
1462 case BATTLEGROUND_NA:
1463 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1464 break;
1465 case BATTLEGROUND_BE:
1466 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1467 break;
1468 case BATTLEGROUND_AA:
1469 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1470 break;
1471 case BATTLEGROUND_EY:
1472 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1473 break;
1474 case BATTLEGROUND_RL:
1475 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1476 break;
1477 case BATTLEGROUND_SA:
1478 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1479 break;
1480 case BATTLEGROUND_DS:
1481 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1482 break;
1483 case BATTLEGROUND_RV:
1484 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1485 break;
1486 default:
1487 //bg = new BattleGround;
1488 return 0;
1489 break; // placeholder for non implemented BG
1492 // generate a new instance id
1493 bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
1495 // reset the new bg (set status to status_wait_queue from status_none)
1496 bg->Reset();
1498 /* will be setup in BG::Update() when the first player is ported in
1499 if(!(bg->SetupBattleGround()))
1501 sLog.outError("BattleGround: CreateNewBattleGround: SetupBattleGround failed for bg %u", bgTypeId);
1502 delete bg;
1503 return 0;
1507 // add BG to free slot queue
1508 bg->AddToBGFreeSlotQueue();
1510 // add bg to update list
1511 AddBattleGround(bg->GetInstanceID(), bg);
1513 return bg;
1516 // used to create the BG templates
1517 uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO)
1519 // Create the BG
1520 BattleGround *bg = NULL;
1522 switch(bgTypeId)
1524 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1525 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1526 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1527 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1528 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1529 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1530 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1531 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1532 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1533 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1534 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1535 default:bg = new BattleGround; break; // placeholder for non implemented BG
1538 bg->SetMapId(MapID);
1540 bg->Reset();
1542 BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId);
1543 //in previous method is checked if exists entry in sBattlemasterListStore, so no check needed
1544 if (bl)
1546 bg->SetArenaorBGType(bl->type == TYPE_ARENA);
1549 bg->SetTypeID(bgTypeId);
1550 bg->SetInstanceID(0); // template bg, instance id is 0
1551 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1552 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1553 bg->SetMinPlayers(MinPlayersPerTeam*2);
1554 bg->SetMaxPlayers(MaxPlayersPerTeam*2);
1555 bg->SetName(BattleGroundName);
1556 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1557 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1558 bg->SetLevelRange(LevelMin, LevelMax);
1560 //add BattleGround instance to FreeSlotQueue (.back() will return the template!)
1561 bg->AddToBGFreeSlotQueue();
1563 // do NOT add to update list, since this is a template battleground!
1565 // return some not-null value, bgTypeId is good enough for me
1566 return bgTypeId;
1569 void BattleGroundMgr::CreateInitialBattleGrounds()
1571 float AStartLoc[4];
1572 float HStartLoc[4];
1573 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1574 BattlemasterListEntry const *bl;
1575 WorldSafeLocsEntry const *start;
1577 uint32 count = 0;
1579 // 0 1 2 3 4 5 6 7 8
1580 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1582 if(!result)
1584 barGoLink bar(1);
1586 bar.step();
1588 sLog.outString();
1589 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1590 return;
1593 barGoLink bar(result->GetRowCount());
1597 Field *fields = result->Fetch();
1598 bar.step();
1600 uint32 bgTypeID = fields[0].GetUInt32();
1602 // can be overwrited by values from DB
1603 bl = sBattlemasterListStore.LookupEntry(bgTypeID);
1604 if(!bl)
1606 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.",bgTypeID);
1607 continue;
1610 MaxPlayersPerTeam = bl->maxplayersperteam;
1611 MinPlayersPerTeam = bl->maxplayersperteam/2;
1612 MinLvl = bl->minlvl;
1613 MaxLvl = bl->maxlvl;
1615 if(fields[1].GetUInt32())
1616 MinPlayersPerTeam = fields[1].GetUInt32();
1618 if(fields[2].GetUInt32())
1619 MaxPlayersPerTeam = fields[2].GetUInt32();
1621 if(fields[3].GetUInt32())
1622 MinLvl = fields[3].GetUInt32();
1624 if(fields[4].GetUInt32())
1625 MaxLvl = fields[4].GetUInt32();
1627 start1 = fields[5].GetUInt32();
1629 start = sWorldSafeLocsStore.LookupEntry(start1);
1630 if(start)
1632 AStartLoc[0] = start->x;
1633 AStartLoc[1] = start->y;
1634 AStartLoc[2] = start->z;
1635 AStartLoc[3] = fields[6].GetFloat();
1637 else if(bgTypeID == BATTLEGROUND_AA)
1639 AStartLoc[0] = 0;
1640 AStartLoc[1] = 0;
1641 AStartLoc[2] = 0;
1642 AStartLoc[3] = fields[6].GetFloat();
1644 else
1646 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.",bgTypeID,start1);
1647 continue;
1650 start2 = fields[7].GetUInt32();
1652 start = sWorldSafeLocsStore.LookupEntry(start2);
1653 if(start)
1655 HStartLoc[0] = start->x;
1656 HStartLoc[1] = start->y;
1657 HStartLoc[2] = start->z;
1658 HStartLoc[3] = fields[8].GetFloat();
1660 else if(bgTypeID == BATTLEGROUND_AA)
1662 HStartLoc[0] = 0;
1663 HStartLoc[1] = 0;
1664 HStartLoc[2] = 0;
1665 HStartLoc[3] = fields[8].GetFloat();
1667 else
1669 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.",bgTypeID,start2);
1670 continue;
1673 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1674 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]))
1675 continue;
1677 ++count;
1678 } while (result->NextRow());
1680 delete result;
1682 sLog.outString();
1683 sLog.outString( ">> Loaded %u battlegrounds", count );
1686 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1688 if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1690 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1691 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1692 if(!result)
1694 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1695 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1696 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"I64FMTD"')", m_NextAutoDistributionTime);
1698 else
1700 m_NextAutoDistributionTime = (*result)[0].GetUInt64();
1701 delete result;
1703 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1707 void BattleGroundMgr::DistributeArenaPoints()
1709 // used to distribute arena points based on last week's stats
1710 sWorld.SendGlobalText("Flushing Arena points based on team ratings, this may take a few minutes. Please stand by...", NULL);
1712 sWorld.SendGlobalText("Distributing arena points to players...", NULL);
1714 //temporary structure for storing maximum points to add values for all players
1715 std::map<uint32, uint32> PlayerPoints;
1717 //at first update all points for all team members
1718 for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
1720 if(ArenaTeam * at = team_itr->second)
1722 at->UpdateArenaPointsHelper(PlayerPoints);
1726 //cycle that gives points to all players
1727 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1729 //update to database
1730 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE `guid` = '%u'", plr_itr->second, plr_itr->first);
1731 //add points if player is online
1732 Player* pl = objmgr.GetPlayer(plr_itr->first);
1733 if (pl)
1734 pl->ModifyArenaPoints(plr_itr->second);
1737 PlayerPoints.clear();
1739 sWorld.SendGlobalText("Finished setting arena points for online players.", NULL);
1741 sWorld.SendGlobalText("Modifying played count, arena points etc. for loaded arena teams, sending updated stats to online players...", NULL);
1742 for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
1744 if(ArenaTeam * at = titr->second)
1746 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1747 at->SaveToDB(); // save changes
1748 at->NotifyStatsChanged(); // notify the players of the changes
1752 sWorld.SendGlobalText("Modification done.", NULL);
1754 sWorld.SendGlobalText("Done flushing Arena points.", NULL);
1757 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, uint32 bgTypeId)
1759 uint32 PlayerLevel = 10;
1761 if(plr)
1762 PlayerLevel = plr->getLevel();
1764 data->Initialize(SMSG_BATTLEFIELD_LIST);
1765 *data << uint64(guid); // battlemaster guid
1766 *data << uint32(bgTypeId); // battleground id
1767 if(bgTypeId == BATTLEGROUND_AA) // arena
1769 *data << uint8(5); // unk
1770 *data << uint32(0); // unk
1772 else // battleground
1774 *data << uint8(0x00); // unk
1776 size_t count_pos = data->wpos();
1777 uint32 count = 0;
1778 *data << uint32(0x00); // number of bg instances
1780 for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
1782 if(itr->second->GetTypeID() == bgTypeId && (PlayerLevel >= itr->second->GetMinLevel()) && (PlayerLevel <= itr->second->GetMaxLevel()))
1784 *data << uint32(itr->second->GetInstanceID());
1785 ++count;
1788 data->put<uint32>( count_pos , count);
1792 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId)
1794 BattleGround *bg = GetBattleGround(instanceId);
1795 if(bg)
1797 uint32 mapid = bg->GetMapId();
1798 float x, y, z, O;
1799 uint32 team = pl->GetBGTeam();
1800 if(team==0)
1801 team = pl->GetTeam();
1802 bg->GetTeamStartLoc(team, x, y, z, O);
1804 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1805 pl->TeleportTo(mapid, x, y, z, O);
1807 else
1809 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1813 void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid)
1815 WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
1816 uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
1817 if(time_ == uint32(-1))
1818 time_ = 0;
1819 data << guid << time_;
1820 pl->GetSession()->SendPacket(&data);
1823 bool BattleGroundMgr::IsArenaType(uint32 bgTypeId)
1825 return ( bgTypeId == BATTLEGROUND_AA ||
1826 bgTypeId == BATTLEGROUND_BE ||
1827 bgTypeId == BATTLEGROUND_NA ||
1828 bgTypeId == BATTLEGROUND_RL );
1831 uint32 BattleGroundMgr::BGQueueTypeId(uint32 bgTypeId, uint8 arenaType)
1833 switch(bgTypeId)
1835 case BATTLEGROUND_WS:
1836 return BATTLEGROUND_QUEUE_WS;
1837 case BATTLEGROUND_AB:
1838 return BATTLEGROUND_QUEUE_AB;
1839 case BATTLEGROUND_AV:
1840 return BATTLEGROUND_QUEUE_AV;
1841 case BATTLEGROUND_EY:
1842 return BATTLEGROUND_QUEUE_EY;
1843 case BATTLEGROUND_SA:
1844 return BATTLEGROUND_QUEUE_SA;
1845 case BATTLEGROUND_AA:
1846 case BATTLEGROUND_NA:
1847 case BATTLEGROUND_RL:
1848 case BATTLEGROUND_BE:
1849 case BATTLEGROUND_DS:
1850 case BATTLEGROUND_RV:
1851 switch(arenaType)
1853 case ARENA_TYPE_2v2:
1854 return BATTLEGROUND_QUEUE_2v2;
1855 case ARENA_TYPE_3v3:
1856 return BATTLEGROUND_QUEUE_3v3;
1857 case ARENA_TYPE_5v5:
1858 return BATTLEGROUND_QUEUE_5v5;
1859 default:
1860 return 0;
1862 default:
1863 return 0;
1867 uint32 BattleGroundMgr::BGTemplateId(uint32 bgQueueTypeId)
1869 switch(bgQueueTypeId)
1871 case BATTLEGROUND_QUEUE_WS:
1872 return BATTLEGROUND_WS;
1873 case BATTLEGROUND_QUEUE_AB:
1874 return BATTLEGROUND_AB;
1875 case BATTLEGROUND_QUEUE_AV:
1876 return BATTLEGROUND_AV;
1877 case BATTLEGROUND_QUEUE_EY:
1878 return BATTLEGROUND_EY;
1879 case BATTLEGROUND_QUEUE_SA:
1880 return BATTLEGROUND_SA;
1881 case BATTLEGROUND_QUEUE_2v2:
1882 case BATTLEGROUND_QUEUE_3v3:
1883 case BATTLEGROUND_QUEUE_5v5:
1884 return BATTLEGROUND_AA;
1885 default:
1886 return 0;
1890 uint8 BattleGroundMgr::BGArenaType(uint32 bgQueueTypeId)
1892 switch(bgQueueTypeId)
1894 case BATTLEGROUND_QUEUE_2v2:
1895 return ARENA_TYPE_2v2;
1896 case BATTLEGROUND_QUEUE_3v3:
1897 return ARENA_TYPE_3v3;
1898 case BATTLEGROUND_QUEUE_5v5:
1899 return ARENA_TYPE_5v5;
1900 default:
1901 return 0;
1905 void BattleGroundMgr::ToggleArenaTesting()
1907 m_ArenaTesting = !m_ArenaTesting;
1908 if(m_ArenaTesting)
1909 sWorld.SendGlobalText("Arenas are set to 1v1 for debugging. So, don't join as group.", NULL);
1910 else
1911 sWorld.SendGlobalText("Arenas are set to normal playercount.", NULL);