root/trunk/src/game/BattleGroundMgr.cpp @ 9

Revision 9, 72.5 kB (checked in by yumileroy, 17 years ago)

[svn] -enabled instantiated battlegrounds
-enabled arena matches
-rewritten battleground queuing to support joining as group
-removed queue announcements

Original author: w12x
Date: 2008-10-05 08:48:32-05:00

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