Show
Ignore:
Timestamp:
11/19/08 13:22:41 (17 years ago)
Author:
yumileroy
Message:

[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

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/src/game/BattleGroundMgr.cpp

    r2 r9  
    3131#include "Policies/SingletonImp.h" 
    3232#include "MapManager.h" 
     33#include "Map.h" 
     34#include "MapInstanced.h" 
    3335#include "ObjectMgr.h" 
    3436#include "ProgressBar.h" 
    3537#include "World.h" 
     38#include "ArenaTeam.h" 
    3639#include "Chat.h" 
    3740 
     
    4548{ 
    4649    //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{ 
    4760    for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++) 
    4861    { 
    49         m_QueuedPlayers[i].Horde = 0; 
    50         m_QueuedPlayers[i].Alliance = 0; 
    51         //m_QueuedPlayers[i].AverageTime = 0; 
    52     } 
    53 } 
    54  
    55 BattleGroundQueue::~BattleGroundQueue() 
    56 { 
    57     for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++) 
    58     { 
    5962        m_QueuedPlayers[i].clear(); 
    60     } 
    61 } 
    62  
    63 void BattleGroundQueue::AddPlayer(Player *plr, uint32 bgTypeId) 
     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) 
    64235{ 
    65236    uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(); 
     
    68239    PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()]; 
    69240    info.InviteTime                 = 0; 
    70     info.IsInvitedToBGInstanceGUID  = 0; 
    71241    info.LastInviteTime             = 0; 
    72242    info.LastOnlineTime             = getMSTime(); 
    73     info.Team                       = plr->GetTeam(); 
    74  
    75     //add player to waiting order queue 
    76     m_PlayersSortedByWaitTime[queue_id].push_back(plr->GetGUID()); 
    77  
    78     if(plr->GetTeam() == ALLIANCE) 
    79         ++m_QueuedPlayers[queue_id].Alliance; 
    80     else 
    81         ++m_QueuedPlayers[queue_id].Horde; 
    82  
    83     this->Update(bgTypeId, queue_id); 
    84  
    85     if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) ) 
    86     { 
    87         BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgTypeId); 
    88         char const* bgName = bg->GetName(); 
    89  
    90         uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id); 
    91         uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id); 
    92  
    93         // replace hardcoded max level by player max level for nice output 
    94         if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) 
    95             q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); 
    96  
    97         int8 MinPlayers = bg->GetMinPlayersPerTeam(); 
    98  
    99         uint8 qHorde = m_QueuedPlayers[queue_id].Horde; 
    100         uint8 qAlliance = m_QueuedPlayers[queue_id].Alliance; 
    101  
    102         // Show queue status to player only (when joining queue) 
    103         if(sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY)) 
    104         { 
    105             ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,  
    106                 bgName, q_min_level, q_max_level, qAlliance, MinPlayers - qAlliance, qHorde, MinPlayers - qHorde); 
    107         } 
    108         // System message 
    109         else 
    110         { 
    111             sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, 
    112                 bgName, q_min_level, q_max_level, qAlliance, MinPlayers - qAlliance, qHorde, MinPlayers - qHorde); 
    113         } 
    114     } 
     243    info.GroupInfo                  = ginfo; 
     244 
     245    // add the pinfo to ginfo's list 
     246    ginfo->Players[plr->GetGUID()]  = &info; 
    115247} 
    116248 
     
    121253    uint32 queue_id = 0; 
    122254    QueuedPlayersMap::iterator itr; 
     255    GroupQueueInfo * group; 
     256    QueuedGroupsList::iterator group_itr; 
    123257    bool IsSet = false; 
    124     if(!plr) 
    125     {                                                       //player is offline, we need to find him somewhere in queues 
    126         /// there is something wrong if this code is run, because we have in queue only online players! 
    127         sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash"); 
     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"); 
    128271        for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++) 
    129272        { 
     
    137280        } 
    138281    } 
    139     else 
    140     {                                                       //player is online, we have his level, so we can find exact queue from his level 
    141         queue_id = plr->GetBattleGroundQueueIdFromLevel(); 
    142         itr = m_QueuedPlayers[queue_id].find(guid); 
    143         IsSet = true; 
    144     } 
    145  
    146     //all variables are set, so remove player 
    147     //remove player from time queue 
    148     m_PlayersSortedByWaitTime[queue_id].remove(guid); 
    149  
    150     if (IsSet && itr != m_QueuedPlayers[queue_id].end()) 
    151     { 
    152         if (!itr->second.IsInvitedToBGInstanceGUID) 
    153         { 
    154             if(itr->second.Team == ALLIANCE) 
    155                 --m_QueuedPlayers[queue_id].Alliance; 
    156             else 
    157                 --m_QueuedPlayers[queue_id].Horde; 
    158         } 
    159         else 
    160         { 
    161             if (decreaseInvitedCount) 
    162             { 
    163                 BattleGround* bg = sBattleGroundMgr.GetBattleGround(itr->second.IsInvitedToBGInstanceGUID); 
     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); 
    164318                if (bg) 
    165                     bg->DecreaseInvitedCount(itr->second.Team); 
    166             } 
    167         } 
     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 
    168330        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        } 
    169515    } 
    170516} 
    171517 
    172518/* 
    173 this method is called when player is inserted, or removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue 
    174 add method calls this by itself, the remove method could works in other way, so you have to call this method from other code after calling remove method 
     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 
    175522*/ 
    176 void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id) 
     523void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating) 
    177524{ 
    178525    if (queue_id >= MAX_BATTLEGROUND_QUEUES) 
     
    184531 
    185532    //if no players in queue ... do nothing 
    186     if (this->m_QueuedPlayers[queue_id].Alliance == 0 && this->m_QueuedPlayers[queue_id].Horde == 0) 
     533    if (this->m_QueuedGroups[queue_id].size() == 0) 
    187534        return; 
    188535 
     536    uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype); 
     537 
    189538    //battleground with free slot for player should be always the last in this queue 
    190     for (BGFreeSlotQueueType::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); ++itr) 
    191     { 
     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; 
    192544        // battleground is running, so if: 
    193545        // DO NOT allow queue manager to invite new player to running arena 
    194         if ((*itr)->isBattleGround() && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE) 
     546        if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE) 
    195547        { 
    196548            //we must check both teams 
     
    198550            // and iterator is invalid 
    199551 
    200             //check if there are some players in queue 
    201             if (m_QueuedPlayers[queue_id].Alliance > 0 || m_QueuedPlayers[queue_id].Horde > 0) 
    202             { 
    203                 for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();) 
     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()) 
    204559                { 
    205                     Player* plr = objmgr.GetPlayer(*itr2); 
    206                     if (!plr) 
    207                     { 
    208                         //something is wrong!, kick player from queue 
    209                         sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug"); 
    210                         uint64 oldval = *itr2; 
    211                         itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2); 
    212                         RemovePlayer(oldval, true); 
    213                         continue; 
    214                     } 
    215  
    216                     // player will be invited, if in bg there is a free slot for him 
    217                     if (bg->HasFreeSlotsForTeam(plr->GetTeam())) 
    218                     { 
    219                         // iterator to player's queue status 
    220                         QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2); 
    221  
    222                         // remove him from time queue 
    223                         itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2); 
    224  
    225                         // only check to be sure ... but this condition shouldn't be true (if it is true, then there is a bug somewhere and pls report it) 
    226                         if (itrPlayerStatus == m_QueuedPlayers[queue_id].end()) 
    227                             continue; 
    228  
    229                         // check if player is not already invited 
    230                         if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID) 
    231                         { 
    232                             itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg->GetInstanceID(); 
    233                             itrPlayerStatus->second.InviteTime = getMSTime(); 
    234                             itrPlayerStatus->second.LastInviteTime = getMSTime(); 
    235                             if(itrPlayerStatus->second.Team == ALLIANCE) 
    236                                 --m_QueuedPlayers[queue_id].Alliance; 
    237                             else 
    238                                 --m_QueuedPlayers[queue_id].Horde; 
    239                             sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID()); 
    240  
    241                             WorldPacket data; 
    242                             uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId); 
    243                             sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0); 
    244                             plr->GetSession()->SendPacket(&data); 
    245                         } 
    246                     } 
    247                     else 
    248                         ++itr2; 
    249  
    250                     //if battleground is FULL, then it is removed from free slot queue - not yet implemented! 
    251                     if (!bg->HasFreeSlots()) 
    252                     { 
    253                         //if bg is full, there is no need to invite other players, so break 
    254                         break; 
    255                         //remove BG from BGFreeSlotQueue - not used now, in this system we don't remove BGs from free queue 
    256                         //bg->RemoveFromBGFreeSlotQueue() --- do not uncomment this - not yet implemented 
    257                     } 
     560                    // if group fits in, invite it 
     561                    InviteGroupToBG((*itr),bg,(*itr)->Team); 
    258562                } 
    259563            } 
    260         } 
    261     } 
    262  
    263     /* THIS IS A CASE THAT IN QUEUE THERE IS ENOUGHT PLAYERS TO START NEW BG */ 
    264     //itr->end is the last BG - template, which is not already started! 
    265  
    266     /* here will be a most of change, when we create battlegrounds instantiated */ 
    267     /* if (there is enough players to start new BG) 
    268         Battleground* newbg = sBattleGroundMgr.CreateNewBattleGround(bgTypeId) 
    269         - that function will use the COPY constructor on BattleGround class ( in bg manager we should have one battleground as a template 
    270             (battleground template will be used only to create new BGs, it will be an instance of BG class, but it won't ever start) */ 
    271  
    272     /* following code is working with current Battleground system and it should be removed, when BGs will work like instances */ 
    273     BattleGround* bg2 = sBattleGroundMgr.GetBattleGround(bgTypeId); 
    274     if (bg2->GetQueueType() != MAX_BATTLEGROUND_QUEUES || bg2->GetStatus() != STATUS_WAIT_QUEUE) 
     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); 
    275579        return; 
    276     if (m_QueuedPlayers[queue_id].Alliance >= bg2->GetMinPlayersPerTeam() && m_QueuedPlayers[queue_id].Horde >= bg2->GetMinPlayersPerTeam()) 
    277     { 
     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 
    278696        bg2->SetStatus(STATUS_WAIT_JOIN); 
    279697        bg2->SetQueueType(queue_id); 
    280  
    281         for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();) 
    282         { 
    283             Player* plr = objmgr.GetPlayer(*itr2); 
    284             if (!plr) 
    285             { 
    286                 //something is wrong!, kick player from queue 
    287                 sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug"); 
    288                 uint64 oldval = *itr2; 
    289                 itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2); 
    290                 RemovePlayer(oldval, true); 
    291                 continue; 
    292             } 
    293  
    294             /* TODO: (i'm not sure this code will be useful: 
    295             here should be some condition like if (bg2->isArena() && bg2->isRated()) 
    296             { 
    297                 invite players from 1 certain group on each faction to play arena match 
    298             } else if ....and existing code 
    299             */ 
    300             // player will be invited, if in bg there is a free slot for him 
    301             if (bg2->HasFreeSlotsForTeam(plr->GetTeam())) 
    302             { 
    303                 // iterator to player's queue status 
    304                 QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2); 
    305  
    306                 // remove him from time queue 
    307                 itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2); 
    308  
    309                 // only check to be sure ... but this condition shouldn't be true (if it is true, then there is a bug somewhere and report it) 
    310                 if (itrPlayerStatus == m_QueuedPlayers[queue_id].end()) 
    311                     continue; 
    312  
    313                 //check if player is not already invited 
    314                 if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID) 
     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) 
    315811                { 
    316                     itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg2->GetInstanceID(); 
    317                     itrPlayerStatus->second.InviteTime = getMSTime(); 
    318                     itrPlayerStatus->second.LastInviteTime = getMSTime(); 
    319  
    320                     if(itrPlayerStatus->second.Team == ALLIANCE) 
    321                         --m_QueuedPlayers[queue_id].Alliance; 
    322                     else 
    323                         --m_QueuedPlayers[queue_id].Horde; 
    324  
    325                     sBattleGroundMgr.InvitePlayer(plr, bg2->GetInstanceID()); 
    326  
    327                     WorldPacket data; 
    328                     uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId); 
    329                     sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0); 
    330                     plr->GetSession()->SendPacket(&data); 
     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; 
    331826                } 
    332827            } 
     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; 
    333835            else 
    334                 ++itr2; 
    335         } 
    336         bg2->StartBattleGround(); 
     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        } 
    337860    } 
    338861} 
     
    362885    if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES)         // player is in queue 
    363886    { 
    364         // 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 
    365         BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()]; 
    366         BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid); 
    367         if (qItr != qpMap.end() && qItr->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID) 
    368         { 
    369             WorldPacket data; 
    370             sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0); 
    371             plr->GetSession()->SendPacket(&data); 
     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            } 
    372900        } 
    373901    } 
     
    397925        return true; 
    398926 
    399     uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID()); 
    400     if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES)         // player is in queue (base at player data 
     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 
    401932    { 
    402933        // 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 
    403         BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()]; 
    404         BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid); 
    405         if (qItr!=qpMap.end() && qItr->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID) 
    406         { 
    407             plr->RemoveBattleGroundQueueId(bg->GetTypeID()); 
    408             sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].RemovePlayer(m_PlayerGuid, true); 
    409             sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].Update(bg->GetTypeID(), bg->GetQueueType()); 
    410  
     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()); 
    411940            WorldPacket data; 
    412             sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_NONE, 0, 0); 
     941            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0); 
    413942            plr->GetSession()->SendPacket(&data); 
    414943        } 
    415944    } 
     945    else 
     946        sLog.outDebug("Battleground: Player was already removed from queue"); 
    416947 
    417948    //event will be deleted 
     
    432963{ 
    433964    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; 
    434972} 
    435973 
    436974BattleGroundMgr::~BattleGroundMgr() 
    437975{ 
    438     for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr) 
    439         delete itr->second; 
     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    } 
    440985    m_BattleGrounds.clear(); 
    441986} 
    442987 
     988// used to update running battlegrounds, and delete finished ones 
    443989void BattleGroundMgr::Update(time_t diff) 
    444990{ 
    445     for(BattleGroundSet::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr) 
     991    BattleGroundSet::iterator itr, next; 
     992    for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next) 
     993    { 
     994        next = itr; 
     995        ++next; 
    446996        itr->second->Update(diff); 
    447 } 
    448  
    449 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2) 
     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) 
    4501039{ 
    4511040    // we can be in 3 queues in same time... 
     
    4611050    *data << uint32(QueueSlot);                             // queue id (0...2) - player can be in 3 queues in time 
    4621051    // uint64 in client 
    463     *data << uint64( uint64(bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) ); 
     1052    *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) ); 
    4641053    *data << uint32(0);                                     // unknown 
    4651054    // alliance/horde for BG and skirmish/rated for Arenas 
    466     *data << uint8(bg->isArena() ? (bg->isRated() ? 1 : 0) : bg->GetTeamIndexByTeamId(team)); 
     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*/ 
    4671101    *data << uint32(StatusID);                              // status 
    4681102    switch(StatusID) 
     
    4941128    data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize())); 
    4951129    *data << uint8(type);                                   // seems to be type (battleground=0/arena=1) 
     1130 
    4961131    if(type)                                                // arena 
    4971132    { 
    498         for(uint8 i = 0; i < 2; i++) 
    499         { 
    500             *data << uint32(3000+1+i);                      // rating change: showed value - 3000 
    501             *data << uint32(0);                             // 2.4.0, has some to do with rating change... 
    502             *data << uint8(0);                              // some unknown string 
     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; 
    5031148        } 
    5041149    } 
     
    5201165        *data << (uint64)itr->first; 
    5211166        *data << (int32)itr->second->KillingBlows; 
    522         if(type) 
    523         { 
    524             // this value is team (green/gold)? 
     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        { 
    5251178            // that part probably wrong 
    526             Player *plr = objmgr.GetPlayer(itr->first); 
    5271179            if(plr) 
    5281180            { 
    529                 if(plr->GetTeam() == HORDE) 
     1181                if(team == HORDE) 
    5301182                    *data << uint8(0); 
    531                 else if(plr->GetTeam() == ALLIANCE) 
     1183                else if(team == ALLIANCE) 
     1184                { 
    5321185                    *data << uint8(1); 
     1186                } 
    5331187                else 
    5341188                    *data << uint8(0); 
     
    5371191                *data << uint8(0); 
    5381192        } 
    539         else 
    540         { 
    541             *data << (int32)itr->second->HonorableKills; 
    542             *data << (int32)itr->second->Deaths; 
    543             *data << (int32)itr->second->BonusHonor;        // bonus honor 
    544         } 
    545         *data << (int32)itr->second->DamageDone;            // damage done 
    546         *data << (int32)itr->second->HealingDone;           // healing done 
    547         switch(bg->GetTypeID())                             // battleground specific things 
     1193        *data << (int32)itr->second->DamageDone;             // damage done 
     1194        *data << (int32)itr->second->HealingDone;            // healing done 
     1195        switch(bg->GetTypeID())                              // battleground specific things 
    5481196        { 
    5491197            case BATTLEGROUND_AV: 
     
    6231271} 
    6241272 
    625 void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID) 
     1273void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team) 
    6261274{ 
    6271275    // set invited player counters: 
     
    6291277    if(!bg) 
    6301278        return; 
    631  
    632     bg->IncreaseInvitedCount(plr->GetTeam()); 
    633     plr->SetInviteForBattleGroundType(bg->GetTypeID()); 
     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 
    6341302    // create invite events: 
    6351303    //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 
    6361304    BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID); 
    6371305    plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME/2)); 
    638     BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, plr->GetTeam()); 
     1306    BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team); 
    6391307    plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME)); 
    6401308} 
    6411309 
     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 
    6421387uint32 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) 
    6431388{ 
     
    6591404 
    6601405    bg->SetMapId(MapID); 
     1406 
    6611407    bg->Reset(); 
    662     if(!bg->SetupBattleGround()) 
    663     { 
    664         delete bg; 
    665         return 0; 
    666     } 
    6671408 
    6681409    BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId); 
     
    6741415 
    6751416    bg->SetTypeID(bgTypeId); 
    676     bg->SetInstanceID(bgTypeId);                            // temporary 
     1417    bg->SetInstanceID(0);                               // template bg, instance id is 0 
    6771418    bg->SetMinPlayersPerTeam(MinPlayersPerTeam); 
    6781419    bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam); 
     
    6831424    bg->SetTeamStartLoc(HORDE,    Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO); 
    6841425    bg->SetLevelRange(LevelMin, LevelMax); 
    685     //add BaggleGround instance to FreeSlotQueue 
     1426 
     1427    //add BattleGround instance to FreeSlotQueue (.back() will return the template!) 
    6861428    bg->AddToBGFreeSlotQueue(); 
    6871429 
    688     AddBattleGround(bg->GetInstanceID(), bg); 
    689     //sLog.outDetail("BattleGroundMgr: Created new battleground: %u %s (Map %u, %u players per team, Levels %u-%u)", bg_TypeID, bg->m_Name, bg->m_MapId, bg->m_MaxPlayersPerTeam, bg->m_LevelMin, bg->m_LevelMax); 
    690     return bg->GetInstanceID(); 
     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;  
    6911434} 
    6921435 
     
    8081551} 
    8091552 
     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 
    8101626void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player* plr, uint32 bgTypeId) 
    8111627{ 
     
    8431659} 
    8441660 
    845 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 bgTypeId) 
    846 { 
    847     BattleGround *bg = GetBattleGround(bgTypeId); 
     1661void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId) 
     1662{ 
     1663    BattleGround *bg = GetBattleGround(instanceId); 
    8481664    if(bg) 
    8491665    { 
    8501666        uint32 mapid = bg->GetMapId(); 
    8511667        float x, y, z, O; 
    852         bg->GetTeamStartLoc(pl->GetTeam(), 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); 
    8531672 
    8541673        sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O); 
    8551674        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); 
    8561679    } 
    8571680} 
     
    8661689    pl->GetSession()->SendPacket(&data); 
    8671690} 
     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}