All pastes #917408 Raw Edit

Mine

public diff v1 · immutable
#917408 ·published 2008-02-25 11:19 UTC
rendered paste body
Index: src/game/ArenaTeam.cpp===================================================================--- src/game/ArenaTeam.cpp	(revision 5306)+++ src/game/ArenaTeam.cpp	(working copy)@@ -51,7 +51,7 @@     if(objmgr.GetArenaTeamByName(ArenaTeamName))            // arena team with this name already exist         return false; -    sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid));+    sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(captainGuid));      CaptainGuid = captainGuid;     Name = ArenaTeamName;@@ -88,11 +88,21 @@     std::string plName;     uint8 plClass; +    if(GetMembersSize() >= GetType() * 2)+    {+        // arena team is full (can't have more than type * 2 players!)+        // return false+        return false;+    }+     if(!objmgr.GetPlayerNameByGUID(PlayerGuid, plName))     // player doesnt exist         return false;                                                             // player already in arenateam of that size-    if(Player::GetArenaTeamIdFromDB(PlayerGuid, GetSlot()) != 0)+    if(Player::GetArenaTeamIdFromDB(PlayerGuid, GetType()) != 0)+    {+        sLog.outError("Arena::AddMember() : player already in this sized team");         return false;+    }      // remove all player signs from another petitions     // this will be prevent attempt joining player to many arenateams and corrupt arena team data integrity@@ -120,6 +130,7 @@     newmember.played_week   = 0;     newmember.wons_season   = 0;     newmember.wons_week     = 0;+    newmember.points_to_add = 0;     members.push_back(newmember);      CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid,guid) VALUES ('%u', '%u')", Id, GUID_LOPART(newmember.guid));@@ -128,10 +139,14 @@     {         pl->SetInArenaTeam(Id, GetSlot());         pl->SetArenaTeamIdInvited(0);+        // personal rating+        pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500);     }     else     {         Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), Id, PlayerGuid);+        // personal rating+        Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500, PlayerGuid);     }      // hide promote/remove buttons@@ -197,7 +212,7 @@ {     Field *fields; -    QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);+    QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season,points_to_add FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);     if(!result)         return; @@ -211,6 +226,7 @@         newmember.wons_week     = fields[2].GetUInt32();         newmember.played_season = fields[3].GetUInt32();         newmember.wons_season   = fields[4].GetUInt32();+        newmember.points_to_add = fields[5].GetUInt32();         members.push_back(newmember);     }while( result->NextRow() );     delete result;@@ -269,13 +285,22 @@     {         player->SetInArenaTeam(0, GetSlot());         player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);+        // delete all info regarding this team+        for(int i = 0; i < 6; ++i)+        {+            player->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0);+            Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0, guid);+        }     }     else     {-        Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), 0, guid);+        // delete all info regarding this team+        for(int i = 0; i < 6; ++i)+            Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0, guid);     } -    CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u'", GUID_LOPART(guid));+    // only delete from this arena team!+    CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u' AND guid = '%u'", GetId(), GUID_LOPART(guid)); }  void ArenaTeam::Disband(WorldSession *session)@@ -302,6 +327,7 @@      CharacterDatabase.BeginTransaction();     CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id);+    CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id);     CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id);     CharacterDatabase.CommitTransaction();     objmgr.RemoveArenaTeam(this);@@ -380,6 +406,18 @@     session->SendPacket(&data); } +void ArenaTeam::NotifyStatsChanged()+{+    // this is called after a rated match ended+    // updates arena team stats for every member of the team (not only the ones who participated!)+    for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+    {+        Player * plr=objmgr.GetPlayer(itr->guid);+        if(plr)+            Stats(plr->GetSession());+    }+}+ void ArenaTeam::InspectStats(WorldSession *session, uint64 guid) {     WorldPacket data(MSG_INSPECT_ARENA_STATS, 8+1+4*6);@@ -387,10 +425,20 @@     data << uint8(GetSlot());                               // slot (0...2)     data << uint32(GetId());                                // arena team id     data << uint32(stats.rating);                           // rating-    data << uint32(stats.games);                            // games-    data << uint32(stats.wins);                             // wins-    data << uint32(stats.played);                           // played (count of all games, that played...)-    data << uint32(0);                                      // unk, 2.3.3+    data << uint32(stats.played);                           // season played+    data << uint32(stats.wins2);                            // season wins+    uint32 participated = 0;+    for(MemberList::iterator itr = members.begin(); itr!= members.end(); ++itr)+    {+        if(itr->guid == guid)+        {+            participated = itr->played_season;+            break;+        }+    }+    data << uint32(participated);                            // played (count of all games, that the inspected member participated...)+    data << uint32(0);                                       // unk, 2.3.3 (personal rating?)+     session->SendPacket(&data); } @@ -468,24 +516,204 @@     } } +uint32 ArenaTeam::GetPoints()+{+    // returns how many points would be awarded with this team type with this rating+    float points;++    if(stats.rating<=1500)+    {+        points = (float)stats.rating * 0.22f + 14.0f;+    }+    else+    {+        points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)stats.rating));+    }++    // type penalties for <5v5 teams+    if(Type == ARENA_TEAM_2v2)+        points *= 0.76f;+    else if(Type == ARENA_TEAM_3v3)+        points *= 0.88f;++    return (uint32) points;+}++float ArenaTeam::GetChanceAgainst(uint32 rating)+{+    // returns the chance to win against a team with the given rating, used in the rating adjustment calculation+    // ELO system+    return 1.0f/(1.0f+exp(log(10.0f)*(float)((float)rating - (float)stats.rating)/400.0f));+}++int32 ArenaTeam::WonAgainstChance(float chance)+{+    // called when the team has won, and had 'chance' calculated chance to beat the opponent+    // calculate the rating modification (ELO system with k=32)+    int32 mod = (int32)(32.0f * (1.0f - chance));+    // modify the team stats accordingly+    stats.rating += mod;+    stats.games += 1;+    stats.wins += 1;+    stats.played += 1;+    stats.wins2 += 1;+/*  this should be done in .flusharenapoints; not a breaker though.+    uint32 higher_rank = 0;+    QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT(arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);+    if(result)+    {+        higher_rank = result->Fetch()->GetUInt32();+        delete result;+    }+    stats.rank = higher_rank + 1;*/+    // return the rating change, used to display it on the results screen+    return mod;+}++int32 ArenaTeam::LostAgainstChance(float chance)+{+    // called when the team has lost, and had 'chance' calculated chance to beat the opponent+    // calculate the rating modification (ELO system with k=32)+    int32 mod = (int32)(32.0f * (0.0f - chance));+    // modify the team stats accordingly+    stats.rating += mod;+    stats.games += 1;+    stats.played += 1;+/*    uint32 higher_rank = 0;+    QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT (arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);+    if(result)+    {+        higher_rank = result->Fetch()->GetUInt32();+        delete result;+    }+    stats.rank = higher_rank + 1;*/+    // return the rating adjustment for display+    return mod;+}++void ArenaTeam::MemberLost(Player * plr, uint32 againstrating)+{+    // called for each participant of a match after losing+    for(MemberList::iterator itr = members.begin(); itr !=  members.end(); ++itr)+    {+        if(itr->guid == plr->GetGUID())+        {+            // update personal rating+            int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);+            float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));+            int32 mod = (int32)(32.0f * (0.0f - chance));+            personalrating += mod;+            if(personalrating < 0)+                personalrating = 0;+            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);+            // update personal played stats+            itr->played_week +=1;+            itr->played_season +=1;+            // update the unit fields+            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);+            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);+            return;+        }+    }+}++void ArenaTeam::MemberWon(Player * plr, uint32 againstrating)+{+    // called for each participant after winning a match+    for(MemberList::iterator itr = members.begin(); itr !=  members.end(); ++itr)+    {+        if(itr->guid == plr->GetGUID())+        {+            // update personal rating+            int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);+            float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));+            int32 mod = (int32)(32.0f * (1.0f - chance));+            personalrating += mod;+            if(personalrating < 0)+                personalrating = 0;+            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);+            // update personal stats+            itr->played_week +=1;+            itr->played_season +=1;+            itr->wons_season += 1;+            itr->wons_week += 1;+            // update unit fields+            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);+            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);+            return;+        }+    }+}++uint32 ArenaTeam::GetMemberPoints(uint64 guid)+{+    // get the points a member should be awarded+    // called from arena point distribution (.flusharenapoints command)+    for(MemberList::iterator itr = members.begin(); itr !=  members.end(); ++itr)+    {+        if(itr->guid == guid)+        {+            return itr->points_to_add;+        }+    }+    return 0;+}++void ArenaTeam::UpdateArenaPointsHelper()+{+    // called after a match has ended and the stats are already modified+    // helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons)+    // 10 played games per week is a minimum+    if(stats.games < 10)+        return;+    // to get points, a player has to participate in at least 30% of the matches+    uint32 min_plays = stats.games * 0.3;+    for(MemberList::iterator itr = members.begin(); itr !=  members.end(); ++itr)+    {+        // the player participated in enough games, update his points+        if(itr->played_week >= min_plays)+        {+            // it's enough to set the points in memory, the saving is done in separate function+            itr->points_to_add = GetPoints();+            // CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->points_to_add,Id, itr->guid);+        }+        // the player failed to participate in enough games, so no points for him+        else+        {+            itr->points_to_add = 0;+        }+    }+}++void ArenaTeam::SaveToDB()+{+    // save team and member stats to db+    // called after a match has ended+    CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", stats.rating, stats.games, stats.played, stats.rank, stats.wins, stats.wins2, GetId());+    for(MemberList::iterator itr = members.begin(); itr !=  members.end(); ++itr)+    {+        CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u', points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->played_week, itr->wons_week, itr->played_season, itr->wons_season, itr->points_to_add, Id, itr->guid);+    }+}+ /* arenateam fields (id from 2.3.3 client): 1414 - arena team id 2v2 1415 - 0=captain, 1=member-1416 - played this season-1417 - played this week+1416 - played this week+1417 - played this season 1418 - unk-1419 - unk+1419 - personal arena rating 1420 - arena team id 3v3 1421 - 0=captain, 1=member-1422 - played this season-1423 - played this week+1422 - played this week+1423 - played this season 1424 - unk-1425 - unk+1425 - personal arena rating 1426 - arena team id 5v5 1427 - 0=captain, 1=member-1428 - played this season-1429 - played this week+1428 - played this week+1429 - played this season 1430 - unk-1431 - unk+1431 - personal arena rating */Index: src/game/ArenaTeam.h===================================================================--- src/game/ArenaTeam.h	(revision 5306)+++ src/game/ArenaTeam.h	(working copy)@@ -92,6 +92,7 @@     uint32 wons_week;     uint32 played_season;     uint32 wons_season;+    uint32 points_to_add; };  struct ArenaTeamStats@@ -145,6 +146,8 @@         void LoadStatsFromDB(uint32 ArenaTeamId);         void LoadPlayerStats(ArenaTeamMember* member); +        void SaveToDB();+         void BroadcastPacket(WorldPacket *packet);          void Roster(WorldSession *session);@@ -152,6 +155,18 @@         void Stats(WorldSession *session);         void InspectStats(WorldSession *session, uint64 guid); +        uint32 GetPoints();+        float GetChanceAgainst(uint32 rating);+        int32 WonAgainstChance(float chance);+        void MemberWon(Player * plr, uint32 againstrating);+        int32 LostAgainstChance(float chance);+        void MemberLost(Player * plr, uint32 againstrating);++        void UpdateArenaPointsHelper();+        uint32 GetMemberPoints(uint64 guid);++        void NotifyStatsChanged();+     protected:          uint32 Id;Index: src/game/ArenaTeamHandler.cpp===================================================================--- src/game/ArenaTeamHandler.cpp	(revision 5306)+++ src/game/ArenaTeamHandler.cpp	(working copy)@@ -111,7 +111,7 @@         return;     } -    if(player->getLevel() != 70)+    if(player->getLevel() < 70)     {         //SendArenaTeamCommandResult(ARENA_TEAM_INVITE_SS,"",Invitedname,ARENA_TEAM_PLAYER_NOT_FOUND_S);                                                             // can't find related opcode@@ -148,6 +148,14 @@         return;     } +    if(arenateam->GetMembersSize() >= arenateam->GetType() * 2)+    {+        // should send an "arena team is full" or the likes message, I just don't know the proper values so... ERR_INTERNAL+//        SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_INTERNAL);+        SendNotification("Your arena team is full, %s cannot join it.", player->GetName());+        return;+    }+     sLog.outDebug("Player %s Invited %s to Join his ArenaTeam", GetPlayer()->GetName(), Invitedname.c_str());      player->SetArenaTeamIdInvited(GetPlayer()->GetArenaTeamId(team_slot));Index: src/game/BattleGround.cpp===================================================================--- src/game/BattleGround.cpp	(revision 5306)+++ src/game/BattleGround.cpp	(working copy)@@ -24,6 +24,7 @@ #include "Language.h"                                       // for chat messages #include "Chat.h" #include "SpellAuras.h"+#include "ArenaTeam.h" #include "World.h"  BattleGround::BattleGround()@@ -45,6 +46,8 @@     m_Name              = "";     m_LevelMin          = 0;     m_LevelMax          = 0;+    m_InBGFreeSlotQueue = false;+    m_SetDeleteThis     = false;      m_MaxPlayersPerTeam = 0;     m_MaxPlayers        = 0;@@ -65,6 +68,12 @@     m_TeamStartLocO[BG_TEAM_ALLIANCE]   = 0;     m_TeamStartLocO[BG_TEAM_HORDE]      = 0; +    m_ArenaTeamIds[BG_TEAM_ALLIANCE]   = 0;+    m_ArenaTeamIds[BG_TEAM_HORDE]      = 0;++    m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE]   = 0;+    m_ArenaTeamRatingChanges[BG_TEAM_HORDE]      = 0;+     m_BgRaids[BG_TEAM_ALLIANCE]         = NULL;     m_BgRaids[BG_TEAM_HORDE]            = NULL; @@ -74,12 +83,34 @@  BattleGround::~BattleGround() {+    // remove objects and creatures+    // (this is done automatically in mapmanager update, when the instance is reset after the reset time)    +    int size = m_BgCreatures.size();+    for(int i = 0; i < size; ++i)+    {+        DelCreature(i);+    }+    size = m_BgObjects.size();+    for(int i = 0; i < size; ++i)+    {+        DelObject(i);+    } +    // delete bound char instances (this should have been already deleted?)+    CharacterDatabase.PExecute("DELETE FROM `character_instance` WHERE `instance` = '%u'", GetInstanceID());+    // delete creature and go respawn times+    WorldDatabase.PExecute("DELETE FROM `creature_respawn` WHERE `instance` = '%u'",GetInstanceID());+    WorldDatabase.PExecute("DELETE FROM `gameobject_respawn` WHERE `instance` = '%u'",GetInstanceID());+    // delete instance from db+    CharacterDatabase.PExecute("DELETE FROM `instance` WHERE id = '%u'",GetInstanceID());+    // remove from battlegrounds+    sBattleGroundMgr.RemoveBattleGround(GetInstanceID());+    // remove from bg free slot queue+    this->RemoveFromBGFreeSlotQueue(); }  void BattleGround::Update(time_t diff) {-     if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())         //BG is empty         return;@@ -236,7 +267,10 @@         if(!self && sender == plr)             continue; -        if(plr->GetTeam() == TeamID)+        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+        if(!team) team = plr->GetTeam();++        if(team == TeamID)             plr->GetSession()->SendPacket(packet);     } }@@ -262,7 +296,10 @@             continue;         } -        if(plr->GetTeam() == TeamID)+        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+        if(!team) team = plr->GetTeam();++        if(team == TeamID)         {             sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);             plr->GetSession()->SendPacket(&data);@@ -282,7 +319,10 @@             continue;         } -        if(plr->GetTeam() == TeamID)+        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+        if(!team) team = plr->GetTeam();+       +        if(team == TeamID)             plr->CastSpell(plr, SpellID, true);     } }@@ -299,7 +339,10 @@             continue;         } -        if(plr->GetTeam() == TeamID)+        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+        if(!team) team = plr->GetTeam();++        if(team == TeamID)             UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);     } }@@ -321,7 +364,10 @@             continue;         } -        if(plr->GetTeam() == TeamID)+        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+        if(!team) team = plr->GetTeam();++        if(team == TeamID)             plr->ModifyFactionReputation(factionEntry, Reputation);     } }@@ -335,13 +381,22 @@  void BattleGround::EndBattleGround(uint32 winner) {+    this->RemoveFromBGFreeSlotQueue();++    ArenaTeam * winner_arena_team = NULL;+    ArenaTeam * loser_arena_team = NULL;+    uint32 loser_rating = 0;+    uint32 winner_rating = 0;     WorldPacket data;     Player *Source = NULL;     const char *winmsg = "";      if(winner == ALLIANCE)     {-        winmsg = GetMangosString(LANG_BG_A_WINS);+        if(isBattleGround())+            winmsg = GetMangosString(LANG_BG_A_WINS);+        else+            winmsg = GetMangosString(LANG_ARENA_GOLD_WINS);          PlaySoundToAll(SOUND_ALLIANCE_WINS);                // alliance wins sound @@ -349,7 +404,10 @@     }     else     {-        winmsg = GetMangosString(LANG_BG_H_WINS);+        if(isBattleGround())+            winmsg = GetMangosString(LANG_BG_H_WINS);+        else+            winmsg = GetMangosString(LANG_ARENA_GREEN_WINS);          PlaySoundToAll(SOUND_HORDE_WINS);                   // horde wins sound @@ -359,6 +417,47 @@     SetStatus(STATUS_WAIT_LEAVE);     m_EndTime = 0; +    // arena rating calculation+    if(isArena() && isRated())+    {+        if(winner == ALLIANCE)+        {+            winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));+            loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));+        }+        else+        {+            winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));+            loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));+        }+        if(winner_arena_team && loser_arena_team)+        {+            loser_rating = loser_arena_team->GetStats().rating;+            winner_rating = winner_arena_team->GetStats().rating;+            float winner_chance = winner_arena_team->GetChanceAgainst(loser_rating);+            float loser_chance = loser_arena_team->GetChanceAgainst(winner_rating);+            int32 winner_change = winner_arena_team->WonAgainstChance(winner_chance);+            int32 loser_change = loser_arena_team->LostAgainstChance(loser_chance);+            if(winner == ALLIANCE)+            {+                SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);+                SetArenaTeamRatingChangeForTeam(HORDE, loser_change);+            }+            else+            {+                SetArenaTeamRatingChangeForTeam(HORDE, winner_change);+                SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);+            }+            winner_arena_team->UpdateArenaPointsHelper();+            loser_arena_team->UpdateArenaPointsHelper();+        }+        else+        {+            SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);+            SetArenaTeamRatingChangeForTeam(HORDE, 0);+        }+    }+     uint32 mark = 0;      for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)@@ -370,14 +469,30 @@             continue;         } +        // should remove spirit of redemption+        if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))+            plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);+         if(!plr->isAlive())         {             plr->ResurrectPlayer(1.0f);             plr->SpawnCorpseBones();         } -        if(plr->GetTeam() == winner)+        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+        if(!team) team = plr->GetTeam();++        // per player calculation+        if(isArena() && isRated() && winner_arena_team && loser_arena_team)         {+            if(team == winner)+                winner_arena_team->MemberWon(plr,loser_rating);+            else+                loser_arena_team->MemberLost(plr,winner_rating);+        }++        if(team == winner)+        {             if(!Source)                 Source = plr;             switch(GetTypeID())@@ -428,10 +543,25 @@         sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);         plr->GetSession()->SendPacket(&data); -        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());+        uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());+        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());         plr->GetSession()->SendPacket(&data);     } +    if(isArena() && isRated() && winner_arena_team && loser_arena_team)+    {+        // save the stat changes+        winner_arena_team->SaveToDB();+        loser_arena_team->SaveToDB();+        // send updated arena team stats to players+        // this way all arena team members will get notified, not only the ones who participated in this match+        winner_arena_team->NotifyStatsChanged();+        loser_arena_team->NotifyStatsChanged();+    }++    // inform invited players about the removal+    sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);+     if(Source)     {         ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_GLOBAL, Source->GetGUID(), winmsg);@@ -448,11 +578,12 @@  void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket) {+    uint32 team = GetPlayerTeam(guid);     // Remove from lists/maps     std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);     if(itr != m_Players.end())     {-        UpdatePlayersCountByTeam(itr->second.Team, true);   // -1 player+        UpdatePlayersCountByTeam(team, true);   // -1 player         m_Players.erase(itr);     } @@ -467,6 +598,10 @@      Player *plr = objmgr.GetPlayer(guid); +    // should remove spirit of redemption+    if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))+        plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);+     if(plr && !plr->isAlive())                              // resurrect on exit     {         plr->ResurrectPlayer(1.0f);@@ -477,41 +612,103 @@      if(plr)     {+        if(!team) team = plr->GetTeam();++        uint32 bgTypeId = GetTypeID();+        uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());+        // if arena, remove the specific arena auras         if(isArena())         {-            if(!sWorld.IsFFAPvPRealm())-                plr->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);+            plr->RemoveArenaAuras(true);    // removes debuffs / dots etc., we don't want the player to die after porting out+            plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);+            plr->RemoveAurasDueToSpell(SPELL_ALLIANCE_GOLD_FLAG);+            plr->RemoveAurasDueToSpell(SPELL_ALLIANCE_GREEN_FLAG);+            plr->RemoveAurasDueToSpell(SPELL_HORDE_GOLD_FLAG);+            plr->RemoveAurasDueToSpell(SPELL_HORDE_GREEN_FLAG);+            bgTypeId=BATTLEGROUND_AA;       // set the bg type to all arenas (it will be used for queue refreshing) -            plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);+            Pet* NewPet = new Pet(plr);+            if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetOldPetNumber(), true))+                delete NewPet;++            (plr)->SetOldPetNumber(0);+            if(isRated() && GetStatus() == STATUS_IN_PROGRESS)+            {+                //left a rated match while the encounter was in progress, consider as loser+                ArenaTeam * winner_arena_team = 0;+                ArenaTeam * loser_arena_team = 0;+                if(team == HORDE)+                {+                    winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));+                    loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));+                }+                else+                {+                    winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));+                    loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));+                }+                if(winner_arena_team && loser_arena_team)+                {+                    loser_arena_team->MemberLost(plr,winner_arena_team->GetRating());+                }+            }         }          WorldPacket data;         if(SendPacket)         {-            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);+            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0);             plr->GetSession()->SendPacket(&data);         }          // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg-        plr->RemoveBattleGroundQueueId(m_TypeID);+        plr->RemoveBattleGroundQueueId(bgQueueTypeId); -        DecreaseInvitedCount(plr->GetTeam());+        DecreaseInvitedCount(team);         //we should update battleground queue, but only if bg isn't ending         if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)-            sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].Update(GetTypeID(), GetQueueType());+            sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueType());          if(!plr->GetBattleGroundId())             return;          Group * group = plr->GetGroup();-         // remove from raid group if exist-        if(group && group == GetBgRaid(plr->GetTeam()))+        if(group && group == GetBgRaid(team))         {+            uint32 groupSize = group->GetMembersCount();+            GroupReference * grpRef = group->GetFirstMember();+            Player * grpGuy = grpRef->getSource();+            // get a member of the group, will be used if the group is disbanded+            // if the one we got is the player, get another+            if(grpGuy->GetGUID()==guid)+            {+                if(grpRef->hasNext()) +                {+                    grpRef = grpRef->next();+                    grpGuy = grpRef->getSource();+                }+                else if(grpRef->hasPrev())+                {+                    grpRef = (GroupReference*)grpRef->prev();+                    grpGuy = grpRef->getSource();+                }+                else+                    grpGuy = NULL;+            }             if(!group->RemoveMember(guid, 0))               // group was disbanded             {-                SetBgRaid(plr->GetTeam(), NULL);+                SetBgRaid(team, NULL);                 delete group;+                if(groupSize >= 2 && grpGuy != 0)                            // someone's still left in the bg, recreate group for him+                {+                    group = new Group;+                    SetBgRaid(team, group);+                    group->ConvertToRaid();+                    group->AddMember(grpGuy->GetGUID(), grpGuy->GetName());+                    group->ChangeLeader(grpGuy->GetGUID());+                    // we don't have to add other players, since the group is only disbanded if the player count before the leave was exactly 2+                }             }         } @@ -520,11 +717,12 @@          // Let others know         sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);-        SendPacketToTeam(plr->GetTeam(), &data, plr, false);+        SendPacketToTeam(team, &data, plr, false);          if(Transport)         {             plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO(), true, false);+            //plr->SetInstanceId(plr->GetBattleGroundEntryPointInstanceId());             //sLog.outDetail("BATTLEGROUND: Sending %s to %f,%f,%f,%f", pl->GetName(), x,y,z,O);         } @@ -532,13 +730,29 @@         sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());     } +    // remove player from bg instance!+    CharacterDatabase.PExecute("DELETE FROM `character_instance` WHERE `guid` = '%u' AND `instance` = '%u'", guid, GetInstanceID());++    if(plr)+    {+        // remove player from bg instance!!!+        plr->m_BoundInstances.erase(GetMapId());+    }+     /// there will be code which will add battleground to BGFreeSlotQueue , when battleground instance will exist     // we always should check if BG is in that queue before adding.. -    if(!GetPlayersSize())+    if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))     {-        Reset();+        // if no players left AND no invitees left, set this bg to delete in next update+        // direct deletion could cause crashes+        m_SetDeleteThis = true;+        // return to prevent addition to freeslotqueue+        return;     }++    // a player exited the battleground, so there are free slots. add to queue+    this->AddToBGFreeSlotQueue(); }  // this method is called when no players remains in battleground@@ -550,6 +764,8 @@     SetStartTime(0);     SetEndTime(0);     SetLastResurrectTime(0);+    SetArenaType(0);+    SetRated(false);      m_Events = 0; @@ -558,11 +774,12 @@      m_InvitedAlliance = 0;     m_InvitedHorde = 0;+    m_InBGFreeSlotQueue = false;      m_Players.clear();     m_PlayerScores.clear(); -    // reset BGSubclass+    // reset BGSubclass (this cleans up creatures and gos as well)     this->ResetBGSubclass(); } @@ -575,52 +792,64 @@      WorldPacket data;     BattleGround *bg = NULL;--    /// this code seems not correct:-    if(GetTypeID() == BATTLEGROUND_AA)-    {-        // we must select one of running arena-        uint8 arenas[3] = { BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL };-        uint8 arena_type = arenas[urand(0, 2)];--        bg = sBattleGroundMgr.GetBattleGround(arena_type);-        if(!bg)-            return;--        bg->SetStatus(STATUS_WAIT_JOIN);--        bg->SetStartTime(0);-        bg->SetLastResurrectTime(0);-    } } -void BattleGround::AddPlayer(Player *plr)+void BattleGround::AddPlayer(Player *plr, uint32 team) {     // score struct must be created in inherited class+    if(team==0)+        team = plr->GetTeam();      uint64 guid = plr->GetGUID();      BattleGroundPlayer bp;     bp.LastOnlineTime = 0;-    bp.Team = plr->GetTeam();+    bp.Team = team;      // Add to list/maps     m_Players[guid] = bp; -    UpdatePlayersCountByTeam(plr->GetTeam(), false);        // +1 player+    UpdatePlayersCountByTeam(team, false);        // +1 player      WorldPacket data;     sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);-    SendPacketToTeam(plr->GetTeam(), &data, plr, false);+    SendPacketToTeam(team, &data, plr, false); +    // add arena specific auras     if(isArena())     {+        plr->RemoveArenaSpellCooldowns();+        plr->RemoveArenaAuras();+        if(team == ALLIANCE && plr->GetTeam() == ALLIANCE)+            plr->CastSpell(plr,SPELL_ALLIANCE_GOLD_FLAG,true);+        else if(team == HORDE && plr->GetTeam() == ALLIANCE)+            plr->CastSpell(plr,SPELL_ALLIANCE_GREEN_FLAG,true);+        else if(team == ALLIANCE && plr->GetTeam() == HORDE)+            plr->CastSpell(plr,SPELL_HORDE_GOLD_FLAG,true);+        else+            plr->CastSpell(plr,SPELL_HORDE_GREEN_FLAG,true);+        plr->DestroyConjuredItems(true);++        Pet* pet = plr->GetPet();+        if(pet)+        {+            if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)+            {+                (plr)->SetOldPetNumber(pet->GetCharmInfo()->GetPetNumber());+                (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));+            }+            (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);+        }+        else+            (plr)->SetOldPetNumber(0);+         if(GetStatus() == STATUS_WAIT_JOIN)                 // not started yet         {-            // temporary disabled-            //plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);+            plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);++            plr->SetHealth(plr->GetMaxHealth());+            plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));         }-        plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);     }      // Log@@ -630,13 +859,20 @@ /* This method should be called only once ... it adds pointer to queue */ void BattleGround::AddToBGFreeSlotQueue() {-    sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);+    // make sure to add only once+    if(!m_InBGFreeSlotQueue)+    {+        sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);+        m_InBGFreeSlotQueue = true;+    } }  /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/ void BattleGround::RemoveFromBGFreeSlotQueue() {-    /* uncomment this code when battlegrounds will work like instances+    // set to be able to re-add if needed+    m_InBGFreeSlotQueue = false;+    // uncomment this code when battlegrounds will work like instances     for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)     {         if ((*itr)->GetInstanceID() == m_InstanceID)@@ -644,7 +880,7 @@             sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);             return;         }-    }*/+    } }  /*@@ -667,6 +903,31 @@     return false; } +// get the number of free slots for team+// works in similar way that HasFreeSlotsForTeam+uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const+{+    //if BG is starting ... invite anyone:+    if (GetStatus() == STATUS_WAIT_JOIN)+        return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;+    //if BG is already started .. do not allow to join too much players of one faction+    uint32 otherTeam;+    if (Team == ALLIANCE)+        otherTeam = GetInvitedCount(HORDE);+    else+        otherTeam = GetInvitedCount(ALLIANCE);+    if (GetStatus() == STATUS_IN_PROGRESS)+    {+        uint32 diff = (otherTeam <= GetInvitedCount(Team)) ? 0 : otherTeam - GetInvitedCount(Team);++        uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;++        return diff < diff2 ? diff : diff2 ;+    }++    return 0;+}+ /* this method isn't called already, it will be useful when more battlegrounds of one type will be available */ bool BattleGround::HasFreeSlots() const {@@ -693,7 +954,9 @@             itr->second->HonorableKills += value;             break;         case SCORE_BONUS_HONOR:                             // Honor bonus-            itr->second->BonusHonor += value;+            // do not add honor in arenas+            if(isBattleGround()) +                itr->second->BonusHonor += value;             break;             //used only in EY, but in MSG_PVP_LOG_DATA opcode         case SCORE_DAMAGE_DONE:                             // Damage Done@@ -747,49 +1010,30 @@  bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 spawntime) {-    GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry);-    if(!goinfo)+    GameObject * go = new GameObject(NULL);+    go->SetInstanceId(GetInstanceID());+    if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, GetMapId(),x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1))     {-        sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);+        sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);+        delete go;         return false;     } -    uint32 guid = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);--    GameObjectData& data = objmgr.NewGOData(guid);--    data.id             = entry;-    data.mapid          = GetMapId();-    data.posX           = x;-    data.posY           = y;-    data.posZ           = z;-    data.orientation    = o;-    data.rotation0      = rotation0;-    data.rotation1      = rotation1;-    data.rotation2      = rotation2;-    data.rotation3      = rotation3;-    data.spawntimesecs  = spawntime;-    data.animprogress   = 100;-    data.go_state       = 1;-    objmgr.AddGameobjectToGrid(guid, &data);--    m_BgObjects[type] = MAKE_GUID(guid, HIGHGUID_GAMEOBJECT);-+    m_BgObjects[type] = go;     return true; }  void BattleGround::DoorOpen(uint32 type) {-    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);+    GameObject *obj = m_BgObjects[type];     if(obj)     {         obj->SetUInt32Value(GAMEOBJECT_FLAGS,33);         obj->SetUInt32Value(GAMEOBJECT_STATE,0);-        //obj->SetLootState(GO_CLOSED);     }     else     {-        sLog.outError("Object not found");+        sLog.outError("Battleground: DoorOpen: Object not found");     } } @@ -797,32 +1041,31 @@ {     if(respawntime == 0)     {-        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);+        GameObject *obj = m_BgObjects[type];         if(obj)         {             //obj->Respawn();                               // bugged             obj->SetRespawnTime(0);-            objmgr.SaveGORespawnTime(obj->GetGUIDLow(), 0, 0);+            objmgr.SaveGORespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);+            MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);         }-        else-            objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, 0);     }     else     {-        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);+        GameObject *obj = m_BgObjects[type];         if(obj)         {             obj->SetRespawnTime(respawntime);             obj->SetLootState(GO_LOOTED);+            MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);         }-        else-            objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, time(NULL) + respawntime);     } } -Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o)+Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime) {     Creature* pCreature = new Creature(NULL);+    pCreature->SetInstanceId(GetInstanceID());     if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMapId(), x, y, z, o, entry, teamval))     {         sLog.outError("Can't create creature entry: %u",entry);@@ -833,17 +1076,42 @@     pCreature->AIM_Initialize();      //pCreature->SetDungeonDifficulty(0);-    MapManager::Instance().GetMap(pCreature->GetMapId(), pCreature)->Add(pCreature);-    m_BgCreatures[type] = pCreature->GetGUID();+    m_BgCreatures[type] = pCreature;+     return  pCreature; } +void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)+{+    if(respawntime == 0)+    {+        Creature *obj = m_BgCreatures[type];+        if(obj)+        {+            //obj->Respawn();                               // bugged+            obj->SetRespawnTime(0);+            objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);+            MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);+        }+    }+    else+    {+        Creature *obj = m_BgCreatures[type];+        if(obj)+        {+            obj->setDeathState(DEAD);+            obj->SetRespawnTime(respawntime);+            MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);+        }+    }+}+ bool BattleGround::DelCreature(uint32 type) {-    Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);+    Creature *cr = m_BgCreatures[type];     if(!cr)     {-        sLog.outError("Can't find creature guid: %u",m_BgCreatures[type]);+        sLog.outError("Can't find creature.");         return false;     }     cr->CleanupsBeforeDelete();@@ -854,10 +1122,10 @@  bool BattleGround::DelObject(uint32 type) {-    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);+    GameObject *obj = m_BgObjects[type];     if(!obj)     {-        sLog.outError("Can't find gobject guid: %u",m_BgObjects[type]);+        sLog.outError("Can't find gobject.");         return false;     }     obj->SetRespawnTime(0);                                 // not save respawn time@@ -927,3 +1195,28 @@ {     return objmgr.GetMangosString(entry); }++// return the player's team based on battlegroundplayer info+// used in same faction arena matches mainly+uint32 BattleGround::GetPlayerTeam(uint64 guid)+{+    std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);+    if(itr!=m_Players.end())+        return itr->second.Team;+    return 0;+}++uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const+{+    int count = 0;+    for(std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)+    {+        if(itr->second.Team == Team)+        {+            Player * pl = objmgr.GetPlayer(itr->first);+            if(pl && pl->isAlive())+                ++count;+        }+    }+    return count;+}Index: src/game/BattleGround.h===================================================================--- src/game/BattleGround.h	(revision 5306)+++ src/game/BattleGround.h	(working copy)@@ -51,7 +51,11 @@     SPELL_SPIRIT_HEAL_CHANNEL       = 22011,     SPELL_SPIRIT_HEAL               = 22012,     SPELL_RESURRECTION_VISUAL       = 24171,-    SPELL_ARENA_PREPARATION         = 32727+    SPELL_ARENA_PREPARATION         = 32728,        // use this one, 32727 causes problems with creature visibility updates, thus client crashes.+    SPELL_ALLIANCE_GOLD_FLAG        = 32724,+    SPELL_ALLIANCE_GREEN_FLAG       = 32725,+    SPELL_HORDE_GOLD_FLAG           = 35774,+    SPELL_HORDE_GREEN_FLAG          = 35775 };  enum BattleGroundTimeIntervals@@ -115,6 +119,18 @@     BATTLEGROUND_RL     = 8 }; +// handle the queue types and bg types separately to enable joining queue for different sized arenas at the same time+enum BattleGroundQueueTypeId+{+    BATTLEGROUND_QUEUE_AV     = 1,+    BATTLEGROUND_QUEUE_WS     = 2,+    BATTLEGROUND_QUEUE_AB     = 3,+    BATTLEGROUND_QUEUE_EY     = 4,+    BATTLEGROUND_QUEUE_2v2     = 5,+    BATTLEGROUND_QUEUE_3v3     = 6,+    BATTLEGROUND_QUEUE_5v5     = 7,+};+ enum ScoreType {     SCORE_KILLING_BLOWS         = 1,@@ -194,6 +210,7 @@     public:         /* Construction */         BattleGround();+        /*BattleGround(const BattleGround& bg);*/         virtual ~BattleGround();         virtual void Update(time_t diff);                   // must be implemented in BG subclass of BG specific update code, but must in begginning call parent version         virtual bool SetupBattleGround()                    // must be implemented in BG subclass@@ -263,6 +280,7 @@         }         bool HasFreeSlotsForTeam(uint32 Team) const;         bool HasFreeSlots() const;+        uint32 GetFreeSlotsForTeam(uint32 Team) const;          bool isArena() const        { return m_IsArena; }         bool isBattleGround() const { return !m_IsArena; }@@ -328,6 +346,7 @@          uint8 GetTeamIndexByTeamId(uint32 Team) const { return Team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE; }         uint32 GetPlayersCountByTeam(uint32 Team) const { return m_PlayersCount[GetTeamIndexByTeamId(Team)]; }+        uint32 GetAlivePlayersCountByTeam(uint32 Team) const;   // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases         void UpdatePlayersCountByTeam(uint32 Team, bool remove)         {             if(remove)@@ -336,6 +355,12 @@                 m_PlayersCount[GetTeamIndexByTeamId(Team)]++;         } +        // used for rated arena battles+        void SetArenaTeamIdForTeam(uint32 Team, uint32 ArenaTeamId) { m_ArenaTeamIds[ Team == ALLIANCE ? 0 : 1] = ArenaTeamId; }+        uint32 GetArenaTeamIdForTeam(uint32 Team) const { return m_ArenaTeamIds[ Team == ALLIANCE ? 0 : 1]; }+        void SetArenaTeamRatingChangeForTeam(uint32 Team, int32 ArenaTeamId) { m_ArenaTeamRatingChanges[ Team == ALLIANCE ? 0 : 1] = ArenaTeamId; }+        uint32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[ Team == ALLIANCE ? 0 : 1]; }+         /* Triggers handle */         // must be implemented in BG subclass         virtual void HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/) {}@@ -344,18 +369,19 @@         // must be implemented in BG subclass if need         virtual void HandleDropFlag(Player* /*player*/) {} -        virtual void AddPlayer(Player *plr);                // must be implemented in BG subclass+        virtual void AddPlayer(Player *plr, uint32 team = 0);                // must be implemented in BG subclass         virtual void RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket);                                                             // can be extended in in BG subclass          // TODO: make this protected:-        typedef std::vector<uint64> BGObjects;-        typedef std::vector<uint64> BGCreatures;+        typedef std::vector<GameObject*> BGObjects;+        typedef std::vector<Creature*> BGCreatures;         BGObjects m_BgObjects;         BGCreatures m_BgCreatures;         void SpawnBGObject(uint32 type, uint32 respawntime);+        void SpawnBGCreature(uint32 type, uint32 respawntime);         bool AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawntime = 0);-        Creature* AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o);+        Creature* AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime = 0);         bool DelCreature(uint32 type);         bool DelObject(uint32 type);         bool AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team);@@ -363,6 +389,11 @@         void DoorOpen(uint32 type);         const char *GetMangosString(uint32 entry); +        // since arenas can be AvA or Hvh, we have to get the "temporary" team of a player+        uint32 GetPlayerTeam(uint64 guid);++        void SetDeleteThis() {m_SetDeleteThis = true;}+     protected:         //this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends BattleGround         void EndNow();@@ -390,6 +421,8 @@         uint32 m_LastResurrectTime;         uint32 m_Queue_type;         uint8  m_ArenaType;                                 // 2=2v2, 3=3v3, 5=5v5+        bool   m_InBGFreeSlotQueue;                         // used to make sure that BG is only once inserted into the BattleGroundMgr.BGFreeSlotQueue[bgTypeId] deque+        bool   m_SetDeleteThis;                             // used for safe deletion of the bg after end / all players leave         // this variable is not used .... it can be found in many other ways... but to store it in BG object instance is useless         //uint8  m_BattleGroundType;                        // 3=BG, 4=arena         //instead of uint8 (in previous line) is bool used@@ -415,6 +448,11 @@         /* Players count by team */         uint32 m_PlayersCount[2]; +        /* Arena team ids by team */+        uint32 m_ArenaTeamIds[2];++        int32 m_ArenaTeamRatingChanges[2];+         /* Limits */         uint32 m_LevelMin;         uint32 m_LevelMax;Index: src/game/BattleGroundAA.cpp===================================================================--- src/game/BattleGroundAA.cpp	(revision 5306)+++ src/game/BattleGroundAA.cpp	(working copy)@@ -35,9 +35,9 @@     BattleGround::Update(diff); } -void BattleGroundAA::AddPlayer(Player *plr)+void BattleGroundAA::AddPlayer(Player *plr, uint32 team) {-    BattleGround::AddPlayer(plr);+    BattleGround::AddPlayer(plr,team);     //create score and add it to map, default values are set in constructor     BattleGroundAAScore* sc = new BattleGroundAAScore; Index: src/game/BattleGroundAA.h===================================================================--- src/game/BattleGroundAA.h	(revision 5306)+++ src/game/BattleGroundAA.h	(working copy)@@ -38,7 +38,7 @@         void Update(time_t diff);          /* inherited from BattlegroundClass */-        virtual void AddPlayer(Player *plr);+        virtual void AddPlayer(Player *plr, uint32 team = 0);         void RemovePlayer(Player *plr, uint64 guid);         void HandleAreaTrigger(Player *Source, uint32 Trigger);         bool SetupBattleGround();Index: src/game/BattleGroundAB.cpp===================================================================--- src/game/BattleGroundAB.cpp	(revision 5306)+++ src/game/BattleGroundAB.cpp	(working copy)@@ -36,6 +36,33 @@  BattleGroundAB::~BattleGroundAB() {+    // despawn objects / creatures here too, maybe the BG ends when the last not-ported invitee leaves the queue+    sLog.outDebug("Arathi Basin: BG ended, objects despawning...");++    // delete everything (for times, when BG will instanced)+    for(uint32 i = 0; i < BG_AB_OBJECT_MAX; i++)+        if (m_bgobjects[i])+        {+            m_bgobjects[i]->SetRespawnTime(0);+            m_bgobjects[i]->Delete();+            m_bgobjects[i] = NULL;+        }++    for(uint32 node = 0; node < BG_AB_NODES_COUNT; node++)+        if (m_bgbuffobjects[node].object)+        {+            m_bgbuffobjects[node].object->SetRespawnTime(0);+            m_bgbuffobjects[node].object->Delete();+            m_bgbuffobjects[node].object = NULL;+        }++    for(uint32 node = 0; node < 7; node++)+        if (m_spiritGuides[node])+        {+            m_spiritGuides[node]->CleanupsBeforeDelete();+            ObjectAccessor::Instance().AddObjectToRemoveList(m_spiritGuides[node]);+            m_spiritGuides[node] = NULL;+        } }  void BattleGroundAB::Update(time_t diff)@@ -205,6 +232,7 @@                 {                     uint8 buff = urand(0, 2);                     m_bgbuffobjects[node].object = new GameObject(NULL);+                    m_bgbuffobjects[node].object->SetInstanceId(GetInstanceID());                     if (!m_bgbuffobjects[node].object->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_BuffObjects[buff][0], GetMapId(), BG_AB_BuffPositions[node][0], BG_AB_BuffPositions[node][1], BG_AB_BuffPositions[node][2], BG_AB_BuffPositions[node][3], 0, 0, sin(BG_AB_BuffPositions[node][3]/2), cos(BG_AB_BuffPositions[node][3]/2), 0, 0))                         ASSERT(0);                     m_bgbuffobjects[node].spellId = BG_AB_BuffObjects[buff][1];@@ -226,6 +254,7 @@                             if (spell)                                 plr->CastSpell(plr, spell, true, 0);                             m_bgbuffobjects[node].timer = BG_AB_BUFF_RESPAWN_TIME;+                            m_bgbuffobjects[node].object->SetRespawnTime(0);                             m_bgbuffobjects[node].object->Delete();                             m_bgbuffobjects[node].object = NULL;                             break;@@ -237,9 +266,9 @@     } } -void BattleGroundAB::AddPlayer(Player *plr)+void BattleGroundAB::AddPlayer(Player *plr, uint32 team) {-    BattleGround::AddPlayer(plr);+    BattleGround::AddPlayer(plr, team);     //create score and add it to map, default values are set in the constructor     BattleGroundABScore* sc = new BattleGroundABScore; @@ -249,7 +278,7 @@ void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) { -    if(GetPlayersSize()==0)+    if(GetPlayersSize()==0 && GetInvitedCount(ALLIANCE)==0 && GetInvitedCount(HORDE)==0)     {         sLog.outDebug("Arathi Basin: BG ended, objects despawning..."); @@ -257,6 +286,7 @@         for(uint32 i = 0; i < BG_AB_OBJECT_MAX; i++)             if (m_bgobjects[i])             {+                m_bgobjects[i]->SetRespawnTime(0);                 m_bgobjects[i]->Delete();                 m_bgobjects[i] = NULL;             }@@ -264,6 +294,7 @@         for(uint32 node = 0; node < BG_AB_NODES_COUNT; node++)             if (m_bgbuffobjects[node].object)             {+                m_bgbuffobjects[node].object->SetRespawnTime(0);                 m_bgbuffobjects[node].object->Delete();                 m_bgbuffobjects[node].object = NULL;             }@@ -276,9 +307,10 @@                 m_spiritGuides[node] = NULL;             } +        // no use, the bg will be deleted soonish         // re-setup-        Reset();-        SetupBattleGround();+        // Reset();+        // SetupBattleGround();                     // Only change back to STATUS_WAIT_QUEUE if successfully re-setuped     } }@@ -342,6 +374,7 @@         else goId = BG_AB_OBJECTID_BANNER_H;      m_bgobjects[obj] = new GameObject(NULL);+    m_bgobjects[obj]->SetInstanceId(GetInstanceID());     m_bgobjects[obj]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), goId, GetMapId(), BG_AB_NodePositions[node][0], BG_AB_NodePositions[node][1], BG_AB_NodePositions[node][2], BG_AB_NodePositions[node][3], 0, 0, sin(BG_AB_NodePositions[node][3]/2), cos(BG_AB_NodePositions[node][3]/2), 100, 1);     MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]); @@ -349,7 +382,8 @@     if (!type)         return;     obj = node*8 + ((type == 3) ? (5 + teamIndex) : 7);-    MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]);+    if(m_bgobjects[obj])+        MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]); }  void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)@@ -357,13 +391,16 @@     uint8 obj = node*8 + type + teamIndex;     if (!m_bgobjects[obj])         return;++    m_bgobjects[obj]->SetRespawnTime(0);     m_bgobjects[obj]->Delete();     m_bgobjects[obj] = NULL;      // handle aura with banner     if (!type) return;     obj = node*8 + ((type == 3) ? (5 + teamIndex) : 7);-    MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Remove(m_bgobjects[obj], false);+    if(m_bgobjects[obj])+        MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Remove(m_bgobjects[obj], false); }  const char* BattleGroundAB::_GetNodeName(uint8 node)@@ -463,6 +500,7 @@     if (m_spiritGuides[node])         return;     m_spiritGuides[node] = new Creature(NULL);+    m_spiritGuides[node]->SetInstanceId(GetInstanceID());     if (!m_spiritGuides[node]->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), 529, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], (node>4)?BG_AB_SpiritGuideId[node-5]:BG_AB_SpiritGuideId[m_Nodes[node]-3], (node>4)?BG_AB_SpiritGuideTeamId[node-5]:BG_AB_SpiritGuideTeamId[m_Nodes[node]-3]))         ASSERT(0);     m_spiritGuides[node]->setDeathState(DEAD);@@ -506,6 +544,7 @@     // despawn buff object     if ((node < BG_AB_NODES_COUNT) && (m_bgbuffobjects[node].object))     {+        m_bgbuffobjects[node].object->SetRespawnTime(0);         m_bgbuffobjects[node].object->Delete();         m_bgbuffobjects[node].object = NULL;     }@@ -626,6 +665,7 @@     for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)     {         m_bgobjects[banner] = new GameObject(NULL);+        m_bgobjects[banner]->SetInstanceId(GetInstanceID());         if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_NODE_BANNER_0+i, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 100, 1))            return false;     }@@ -634,27 +674,32 @@     for (int banner = BG_AB_OBJECT_AURA_ALLY, i = 0; i < 5; banner += 8, ++i)     {         m_bgobjects[banner] = new GameObject(NULL);+        m_bgobjects[banner]->SetInstanceId(GetInstanceID());         if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_A, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0))            return false;     }     for (int banner = BG_AB_OBJECT_AURA_HORDE, i = 0; i < 5; banner += 8, ++i)     {         m_bgobjects[banner] = new GameObject(NULL);+        m_bgobjects[banner]->SetInstanceId(GetInstanceID());         if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_H, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0))            return false;     }     for (int banner = BG_AB_OBJECT_AURA_CONTESTED, i = 0; i < 5; banner += 8, ++i)     {         m_bgobjects[banner] = new GameObject(NULL);+        m_bgobjects[banner]->SetInstanceId(GetInstanceID());         if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_C, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0))            return false;     }      // Starting gates     m_bgobjects[BG_AB_OBJECT_GATE_A] = new GameObject(NULL);+    m_bgobjects[BG_AB_OBJECT_GATE_A]->SetInstanceId(GetInstanceID());     if(!m_bgobjects[BG_AB_OBJECT_GATE_A]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_GATE_A, GetMapId(), BG_AB_DoorPositions[0][0], BG_AB_DoorPositions[0][1], BG_AB_DoorPositions[0][2], BG_AB_DoorPositions[0][3], BG_AB_DoorPositions[0][4], BG_AB_DoorPositions[0][5], BG_AB_DoorPositions[0][6], BG_AB_DoorPositions[0][7], 100, 1))         return false;     m_bgobjects[BG_AB_OBJECT_GATE_H] = new GameObject(NULL);+    m_bgobjects[BG_AB_OBJECT_GATE_H]->SetInstanceId(GetInstanceID());     if(!m_bgobjects[BG_AB_OBJECT_GATE_H]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_GATE_H, GetMapId(), BG_AB_DoorPositions[1][0], BG_AB_DoorPositions[1][1], BG_AB_DoorPositions[1][2], BG_AB_DoorPositions[1][3], BG_AB_DoorPositions[1][4], BG_AB_DoorPositions[1][5], BG_AB_DoorPositions[1][6], BG_AB_DoorPositions[1][7], 100, 1))         return false; @@ -757,3 +802,7 @@   ++++Index: src/game/BattleGroundAB.h===================================================================--- src/game/BattleGroundAB.h	(revision 5306)+++ src/game/BattleGroundAB.h	(working copy)@@ -222,7 +222,7 @@         ~BattleGroundAB();          void Update(time_t diff);-        void AddPlayer(Player *plr);+        void AddPlayer(Player *plr, uint32 team = 0);         void RemovePlayer(Player *plr,uint64 guid);         void HandleAreaTrigger(Player *Source, uint32 Trigger);         virtual bool SetupBattleGround();Index: src/game/BattleGroundAV.cpp===================================================================--- src/game/BattleGroundAV.cpp	(revision 5306)+++ src/game/BattleGroundAV.cpp	(working copy)@@ -39,9 +39,9 @@     BattleGround::Update(diff); } -void BattleGroundAV::AddPlayer(Player *plr)+void BattleGroundAV::AddPlayer(Player *plr, uint32 team) {-    BattleGround::AddPlayer(plr);+    BattleGround::AddPlayer(plr, team);     //create score and add it to map, default values are set in constructor     BattleGroundAVScore* sc = new BattleGroundAVScore; Index: src/game/BattleGroundAV.h===================================================================--- src/game/BattleGroundAV.h	(revision 5306)+++ src/game/BattleGroundAV.h	(working copy)@@ -45,7 +45,7 @@         void Update(time_t diff);          /* inherited from BattlegroundClass */-        virtual void AddPlayer(Player *plr);+        virtual void AddPlayer(Player *plr, uint32 team = 0);          void RemovePlayer(Player *plr,uint64 guid);         void HandleAreaTrigger(Player *Source, uint32 Trigger);Index: src/game/BattleGroundBE.cpp===================================================================--- src/game/BattleGroundBE.cpp	(revision 5306)+++ src/game/BattleGroundBE.cpp	(working copy)@@ -89,6 +89,11 @@                 if(plr)                     plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);             }++            if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+                EndBattleGround(HORDE);+            else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))+                EndBattleGround(ALLIANCE);         }     } @@ -98,9 +103,9 @@     }*/ } -void BattleGroundBE::AddPlayer(Player *plr)+void BattleGroundBE::AddPlayer(Player *plr, uint32 team) {-    BattleGround::AddPlayer(plr);+    BattleGround::AddPlayer(plr, team);     //create score and add it to map, default values are set in constructor     BattleGroundBEScore* sc = new BattleGroundBEScore; @@ -109,7 +114,13 @@  void BattleGroundBE::RemovePlayer(Player *plr, uint64 guid) {+    if(GetStatus() == STATUS_WAIT_LEAVE)+        return; +    if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+        EndBattleGround(HORDE);+    else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))+        EndBattleGround(ALLIANCE); }  void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer)@@ -123,15 +134,16 @@         return;     } -    uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());--    m_TeamKills[killer_team_index]++;                       // add kills to killer's team--    if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))+    if(!GetAlivePlayersCountByTeam(ALLIANCE))     {         // all opponents killed-        EndBattleGround(killer->GetTeam());+        EndBattleGround(HORDE);     }+    else if(!GetAlivePlayersCountByTeam(HORDE))+    {+        // all opponents killed+        EndBattleGround(ALLIANCE);+    } }  void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger)@@ -141,14 +153,14 @@         return;      uint32 SpellId = 0;-    uint64 buff_guid = 0;+    GameObject* obj = 0;     switch(Trigger)     {         case 4538:                                          // buff trigger?-            buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_1];+            obj = m_BgObjects[BG_BE_OBJECT_BUFF_1];             break;         case 4539:                                          // buff trigger?-            buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_2];+            obj = m_BgObjects[BG_BE_OBJECT_BUFF_2];             break;         default:             sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);@@ -156,11 +168,8 @@             break;     } -    if(buff_guid)+    if(obj)     {-        GameObject *obj = HashMapHolder<GameObject>::Find(buff_guid);-        if(obj)-        {             if(!obj->isSpawned())                 return;                                     // buff not spawned yet             obj->SetRespawnTime(BUFF_RESPAWN_TIME);@@ -168,14 +177,12 @@             SpellId = obj->GetGOInfo()->data3;             if(SpellId)                 Source->CastSpell(Source, SpellId, true);-        }     } }  void BattleGroundBE::ResetBGSubclass() {-    m_TeamKills[BG_TEAM_ALLIANCE] = 0;-    m_TeamKills[BG_TEAM_HORDE]    = 0;+ }  bool BattleGroundBE::SetupBattleGround()Index: src/game/BattleGroundBE.h===================================================================--- src/game/BattleGroundBE.h	(revision 5306)+++ src/game/BattleGroundBE.h	(working copy)@@ -58,7 +58,7 @@         void Update(time_t diff);          /* inherited from BattlegroundClass */-        virtual void AddPlayer(Player *plr);+        virtual void AddPlayer(Player *plr, uint32 team = 0);          void RemovePlayer(Player *plr, uint64 guid);         void HandleAreaTrigger(Player *Source, uint32 Trigger);@@ -68,8 +68,5 @@          /* Scorekeeping */         void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);--    private:-        uint32 m_TeamKills[2];                              // count of kills for each team }; #endifIndex: src/game/BattleGroundEY.cpp===================================================================--- src/game/BattleGroundEY.cpp	(revision 5306)+++ src/game/BattleGroundEY.cpp	(working copy)@@ -39,9 +39,9 @@     BattleGround::Update(diff); } -void BattleGroundEY::AddPlayer(Player *plr)+void BattleGroundEY::AddPlayer(Player *plr, uint32 team) {-    BattleGround::AddPlayer(plr);+    BattleGround::AddPlayer(plr, team);     //create score and add it to map     BattleGroundEYScore* sc = new BattleGroundEYScore; Index: src/game/BattleGroundEY.h===================================================================--- src/game/BattleGroundEY.h	(revision 5306)+++ src/game/BattleGroundEY.h	(working copy)@@ -39,7 +39,7 @@         void Update(time_t diff);          /* inherited from BattlegroundClass */-        virtual void AddPlayer(Player *plr);+        virtual void AddPlayer(Player *plr, uint32 team = 0);          void RemovePlayer(Player *plr,uint64 guid);         void HandleAreaTrigger(Player *Source, uint32 Trigger);Index: src/game/BattleGroundHandler.cpp===================================================================--- src/game/BattleGroundHandler.cpp	(revision 5306)+++ src/game/BattleGroundHandler.cpp	(working copy)@@ -26,9 +26,12 @@ #include "MapManager.h" #include "ObjectAccessor.h" #include "Object.h"+#include "Chat.h"+#include "Language.h" #include "BattleGroundMgr.h" #include "BattleGroundWS.h" #include "BattleGround.h"+#include "ArenaTeam.h"  void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data ) {@@ -78,8 +81,17 @@     recv_data >> instanceId;                                // instance id, 0 if First Available selected     recv_data >> joinAsGroup;                               // join as group +    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)+    {+        sLog.outError("bgport: invalid bgtype received. possible cheater? player guid %u",_player->GetGUIDLow());+        return;+    }+     sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT, guid); +    // can do this, since it's battleground, not arena+    uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, 0);+     // ignore if we already in BG or BG queue     if(_player->InBattleGround())         return;@@ -100,19 +112,39 @@         return;     } -    // check existence-    BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);-    if(!bg)+    // get bg instance or bg template if instance not found+    BattleGround * bg = 0;+    if(instanceId)+        BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);++    if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))+    {+        sLog.outError("Battleground: no available bg / template found");         return;+    }      if(joinAsGroup && _player->GetGroup())     {         Group *grp = _player->GetGroup();+        if(grp->GetMembersCount() > bg->GetMaxPlayersPerTeam())+        {+            WorldPacket data;+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_BG_GROUP_TOO_LARGE), NULL);+            SendPacket(&data);+            return;+        }+        GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);         for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())         {             Player *member = itr->getSource();             if(!member) continue; +            if( member->GetBattleGroundQueueIdFromLevel() != _player->GetBattleGroundQueueIdFromLevel() )+                continue;++            if( member->GetTeam() != _player->GetTeam() )+                continue;+             if( !member->CanJoinToBattleground() )             {                 WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);@@ -120,12 +152,12 @@                 _player->GetSession()->SendPacket(&data);                 continue;             }-            if (member->GetBattleGroundQueueIndex(bgTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)+            if (member->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)                 //player is already in this queue                 continue;              WorldPacket data;-            uint32 queueSlot = member->AddBattleGroundQueueId(bgTypeId);           // add to queue+            uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);           // add to queue             if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)             {                 // fill data packet@@ -134,22 +166,23 @@             }              // store entry point coords (same as leader entry point)-            member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());+            member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());                                                              // send status packet (in queue)             sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);             member->GetSession()->SendPacket(&data);             sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);             member->GetSession()->SendPacket(&data);-            sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(member, bgTypeId);+            sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);         }+        sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());     }     else     {-        if (_player->GetBattleGroundQueueIndex(bgTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)+        if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)             //player is already in this queue             return;-        uint32 queueSlot = _player->AddBattleGroundQueueId(bgTypeId);+        uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);         if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)         {             WorldPacket data;@@ -159,13 +192,16 @@         }          // store entry point coords-        _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());+        _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());          WorldPacket data;                                                             // send status packet (in queue)         sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);         SendPacket(&data);-        sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(_player, bgTypeId);++        GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);+        sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);+        sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());     } } @@ -247,6 +283,12 @@     uint32 bgTypeId;     recv_data >> bgTypeId;                                  // id from DBC +    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)+    {+        sLog.outError("Battleground: invalid bgtype received.");+        return;+    }+     BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);      if(!bl)@@ -263,39 +305,151 @@      sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); -    uint8 unk1;+    uint8 type;                                             // arenatype if arena     uint8 unk2;                                             // unk, can be 0x0 (may be if was invited?) and 0x1+    uint32 instanceId;                                           uint32 bgTypeId;                                        // type id from dbc     uint16 unk;                                             // 0x1F90 constant?     uint8 action;                                           // enter battle 0x1, leave queue 0x0 -    recv_data >> unk1 >> unk2 >> bgTypeId >> unk >> action;+    recv_data >> type >> unk2 >> bgTypeId >> unk >> action; -    BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);+    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)+    {+        sLog.outError("Battleground: invalid bgtype received.");+        // update battleground slots for the player to fix his UI and sent data.+        // this is a HACK, I don't know why the client starts sending invalid packets in the first place.+        // it usually happens with extremely high latency (if debugging / stepping in the code for example)+        if(_player->InBattleGroundQueue())+        {+            // update all queues, send invitation info if player is invited, queue info if queued+            for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)+            {+                uint32 queue_id = _player->GetBattleGroundQueueId(i);+                if(!queue_id)+                    continue;+                BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());+                // if the player is not in queue, contine+                if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())+                    continue;++                // no group information, this should never happen+                if(!itrPlayerStatus->second.GroupInfo)+                    continue;++                BattleGround * bg = NULL;++                // get possibly needed data from groupinfo+                bgTypeId = itrPlayerStatus->second.GroupInfo->BgTypeId;+                uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;+                uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated;+                uint8 status = 0;++                +                if(!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)+                {+                    // not invited to bg, get template+                    bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);+                    status = STATUS_WAIT_QUEUE;+                }+                else+                {+                    // get the bg we're invited to+                    BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID);+                    status = STATUS_WAIT_JOIN;+                }++                // if bg not found, then continue+                if(!bg)+                    continue;++                // don't invite if already in the instance+                if(_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID())+                    continue;++                // re - invite player with proper data+                WorldPacket data;+                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, itrPlayerStatus->second.GroupInfo->Team?itrPlayerStatus->second.GroupInfo->Team:_player->GetTeam(), i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype, israted);+                SendPacket(&data);+            }+        }+        return;+    }++    uint32 bgQueueTypeId = 0;+    // get the bg what we were invited to +    BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus;+    bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId,type);+    itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());++    if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())+    {+        sLog.outError("Battleground: itrplayerstatus not found.");+        return;+    }+    instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;++    // if action == 1, then instanceId is _required_+    if(!instanceId && action == 1)+    {+        sLog.outError("Battleground: instance not found.");+        return;+    }++    BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);++    // bg template might and must be used in case of leaving queue, when instance is not created yet+    if(!bg && action == 0)+        bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);++    if(!bg)+    {+        sLog.outError("Battleground: bg not found.");+        return;+    }++    bgTypeId = bg->GetTypeID();     if(bg)     {         if(_player->InBattleGroundQueue())         {             uint32 queueSlot = 0;+            uint32 team = 0;+            uint32 arenatype = 0;+            uint32 israted = 0;+            // get the team info from the queue+            BattleGroundQueue::QueuedPlayersMap::iterator pitr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());+            if(pitr !=sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end()+                && pitr->second.GroupInfo )+            {+                team = pitr->second.GroupInfo->Team;+                arenatype = pitr->second.GroupInfo->ArenaType;+                israted = pitr->second.GroupInfo->IsRated;+            }+            else+            {+                sLog.outError("Battleground: Invalid player queue info!");+                return;+            }             WorldPacket data;             switch(action)             {                 case 1:                                     // port to battleground                     _player->RemoveFromGroup();-                    queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);+                    queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);                     sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());                     _player->GetSession()->SendPacket(&data);                     // remove battleground queue status from BGmgr-                    sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), false);-                    // check if player is not deserter-                    if( !_player->CanJoinToBattleground() )+                    sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);+                    // check if player is not deserter -- check in signup, not here!+                    /*if( !_player->CanJoinToBattleground() )                     {                         WorldPacket data2;                         data2.Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);                         data2 << (uint32) 0xFFFFFFFE;                         SendPacket(&data2);                         return;-                    }+                    }*/                     // if player is in battleground already, remove him and port him to new battleground                     if ( _player->InBattleGround() )                     {@@ -303,15 +457,15 @@                         if (currentBg)                             currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);                     }-                    _player->SetBattleGroundId(bg->GetTypeID());-                    sBattleGroundMgr.SendToBattleGround(_player, bgTypeId);-                    bg->AddPlayer(_player);+                    _player->SetBattleGroundId(bg->GetInstanceID());+                    sBattleGroundMgr.SendToBattleGround(_player, instanceId, team);+                    bg->AddPlayer(_player,team);                     break;                 case 0:                                     // leave queue-                    queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);-                    _player->RemoveBattleGroundQueueId(bgTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs+                    queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);+                    _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs                     sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);-                    sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), true);+                    sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);                     SendPacket(&data);                     break;                 default:@@ -350,7 +504,8 @@         BattleGround *bg = _player->GetBattleGround();         if(bg)         {-            uint32 queueSlot = _player->GetBattleGroundQueueIndex(bg->GetTypeID());+            uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());+            uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);             if((bg->GetStatus() <= STATUS_IN_PROGRESS))             {                 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());@@ -358,15 +513,25 @@             }             for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)             {-                uint32 queue_id = _player->GetBattleGroundQueueId(i);-                if (i == queueSlot || !queue_id)+                uint32 queue_id = _player->GetBattleGroundQueueId(i);       // battlegroundqueueid stores the type id, not the instance id, so this is definitely wrong+                uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);+                uint8 isRated = 0;+                if (i == queueSlot || !queue_id)                            // we need to get the instance ids                     continue;-                BattleGround *bg2 = sBattleGroundMgr.GetBattleGround(queue_id);+                BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());+                if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())+                    continue;+                if(itrPlayerStatus->second.GroupInfo)+                {+                    arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;+                    isRated = itrPlayerStatus->second.GroupInfo->IsRated;+                }+                BattleGround *bg2 = sBattleGroundMgr.GetBattleGroundTemplate(sBattleGroundMgr.BGTemplateId(queue_id)); //  try this                 if(bg2)                 {                     //in this call is small bug, this call should be filled by player's waiting time in queue                     //this call nulls all timers for client :-                    sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);+                    sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0,arenatype,isRated);                     SendPacket(&data);                 }             }@@ -378,18 +543,34 @@         for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)         {             uint32 queue_id = _player->GetBattleGroundQueueId(i);-            BattleGround *bg = sBattleGroundMgr.GetBattleGround(queue_id);+            if(!queue_id)+                continue;+            uint32 bgTypeId = sBattleGroundMgr.BGTemplateId(queue_id);+            uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);+            uint8 isRated = 0;+            BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);+            BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());+            if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())+                continue;+            if(itrPlayerStatus->second.GroupInfo)+            {+                arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;+                isRated = itrPlayerStatus->second.GroupInfo->IsRated;+            }             if(bg && queue_id)             {-                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);+                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);                 SendPacket(&data);             }         }     }-    /*else              // not sure if it needed...+/*    else              // not sure if it needed...     {-        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(), STATUS_NONE, 0, 0);-        SendPacket(&data);+        for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)+        {+            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(),i , STATUS_NONE, 0, 0);+            SendPacket(&data);+        }     }*/ } @@ -453,7 +634,7 @@     recv_data.hexlike();      // ignore if we already in BG or BG queue-    if(_player->InBattleGround() || _player->InBattleGroundQueue())+    if(_player->InBattleGround())         return;      uint64 guid;                                            // arena Battlemaster guid@@ -470,6 +651,7 @@         return;      uint8 arenatype = 0;+    uint32 arenaRating = 0;      switch(type)     {@@ -487,23 +669,72 @@             break;     } -    if(isRated && !_player->GetArenaTeamId(type))           // player not in arena team of that size+    if(isRated)           // player not in arena team of that size     {-        _player->GetSession()->SendNotInArenaTeamPacket(arenatype);-        return;+        uint32 ateamId = _player->GetArenaTeamId(type);+        if(!ateamId)+        {+            _player->GetSession()->SendNotInArenaTeamPacket(arenatype);+            return;+        }+        ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);+        if(!at)+        {+            _player->GetSession()->SendNotInArenaTeamPacket(arenatype);+            return;+        }+        arenaRating = at->GetRating();+        Group *grp = _player->GetGroup();+        if(grp)+        {+            for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())+            {+                Player *member = itr->getSource();++                // offline member or not in team -> err+                if(!member || member->GetArenaTeamId(type) != ateamId)+                {+                    WorldPacket data;+                    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_ARENA_YOUR_TEAM_ONLY), NULL);+                    SendPacket(&data);+                    return;+                }+            }+            if(grp->GetMembersCount() < arenatype)+            {+                WorldPacket data;+                ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_ARENA_NOT_ENOUGH_PLAYERS), NULL);+                SendPacket(&data);+                return;+            }+        }     }      if(asGroup && !_player->GetGroup())                     // player not in group         return; -    // check existence-    BattleGround *bg = sBattleGroundMgr.GetBattleGround(BATTLEGROUND_AA);-    if(!bg)+    //check existance+    BattleGround* bg = NULL;+    if( !(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)) )+    {+        sLog.outError("Battleground: template bg (all arenas) not found");              return;+    } +    uint8 bgTypeId = bg->GetTypeID();+    uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);+     if(asGroup && _player->GetGroup())     {         Group *grp = _player->GetGroup();+        if(grp->GetMembersCount() > arenatype)+        {+            WorldPacket data;+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_ARENA_GROUP_TOO_LARGE), NULL);+            SendPacket(&data);+            return;+        }+        GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating);         for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())         {             Player *member = itr->getSource();@@ -513,11 +744,19 @@                 //player has deserter aura .. do nothing             */ -            if (member->GetBattleGroundQueueIndex(BATTLEGROUND_AA) < PLAYER_MAX_BATTLEGROUND_QUEUES)+            if( member->GetBattleGroundQueueIdFromLevel() != _player->GetBattleGroundQueueIdFromLevel() )+                continue;++            if( member->GetTeam() != _player->GetTeam() )+                continue;++            if (member->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)+            {                 //player is already in this queue                 continue;+            } -            uint32 queueSlot = member->AddBattleGroundQueueId(BATTLEGROUND_AA);// add to queue+            uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue             if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)             {                 WorldPacket data;@@ -527,16 +766,17 @@             }              // store entry point coords (same as leader entry point)-            member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());+            member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());              WorldPacket data;             // send status packet (in queue)-            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);+            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);             member->GetSession()->SendPacket(&data);-            sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, BATTLEGROUND_AA);+            sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);             member->GetSession()->SendPacket(&data);-            sBattleGroundMgr.m_BattleGroundQueues[BATTLEGROUND_AA].AddPlayer(member, BATTLEGROUND_AA);+            sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);         }+        sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);     }     else     {@@ -544,11 +784,13 @@             //player has deserter aura .. do nothing         */ -        if (_player->GetBattleGroundQueueIndex(BATTLEGROUND_AA) < PLAYER_MAX_BATTLEGROUND_QUEUES)+        if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)+        {             //player is already in this queue             return;+        } -        uint32 queueSlot = _player->AddBattleGroundQueueId(BATTLEGROUND_AA);+        uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);         if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)         {             WorldPacket data;@@ -558,12 +800,14 @@         }          // store entry point coords-        _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());+        _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());          WorldPacket data;         // send status packet (in queue)-        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);+        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);         SendPacket(&data);-        sBattleGroundMgr.m_BattleGroundQueues[BATTLEGROUND_AA].AddPlayer(_player, BATTLEGROUND_AA);+        GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating);+        sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);+        sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);     } }Index: src/game/BattleGroundMgr.cpp===================================================================--- src/game/BattleGroundMgr.cpp	(revision 5306)+++ src/game/BattleGroundMgr.cpp	(working copy)@@ -30,9 +30,12 @@ #include "SharedDefines.h" #include "Policies/SingletonImp.h" #include "MapManager.h"+#include "Map.h"+#include "MapInstanced.h" #include "ObjectMgr.h" #include "ProgressBar.h" #include "World.h"+#include "ArenaTeam.h"  INSTANTIATE_SINGLETON_1( BattleGroundMgr ); @@ -43,12 +46,12 @@ BattleGroundQueue::BattleGroundQueue() {     //queues are empty, we don't have to call clear()-    for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)+/*    for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)     {-        m_QueuedPlayers[i].Horde = 0;-        m_QueuedPlayers[i].Alliance = 0;+        //m_QueuedPlayers[i].Horde = 0;+        //m_QueuedPlayers[i].Alliance = 0;         //m_QueuedPlayers[i].AverageTime = 0;-    }+    }*/ }  BattleGroundQueue::~BattleGroundQueue()@@ -56,35 +59,187 @@     for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)     {         m_QueuedPlayers[i].clear();+        for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr)+        {+            delete (*itr);+        }+        m_QueuedGroups[i].clear();     } } -void BattleGroundQueue::AddPlayer(Player *plr, uint32 bgTypeId)+// initialize eligible groups from the given source matching the given specifications+void BattleGroundQueue::EligibleGroups::Init(BattleGroundQueue::QueuedGroupsList *source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType, bool IsRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime) {+    // clear from prev initialization+    clear();+    BattleGroundQueue::QueuedGroupsList::iterator itr, next;+    // iterate through the source+    for(itr = source->begin(); itr!= source->end(); itr = next)+    {+        next = itr;+        ++next;+        if( (*itr)->BgTypeId == BgTypeId &&+            (*itr)->ArenaType == ArenaType &&+            (*itr)->IsRated == IsRated &&+            (*itr)->IsInvitedToBGInstanceGUID == 0 &&+            (*itr)->Team == side &&+            (*itr)->Players.size() <= MaxPlayers &&+            ((*itr)->JoinTime <= DisregardTime              // pass if disregard time is greater than join time+            || (*itr)->ArenaTeamRating == 0                 // pass if no rating info+            || ((*itr)->ArenaTeamRating >= MinRating        +            && ((*itr)->ArenaTeamRating <= MaxRating))) )   // pass if matches the rating range+        {+            // the group matches the conditions+            // insert it in order of groupsize, and join time+            uint32 size = (*itr)->Players.size();+            uint32 jointime = (*itr)->JoinTime;+            bool inserted = false;++            for(std::list<GroupQueueInfo *>::iterator elig_itr = begin(); elig_itr != end(); ++elig_itr)+            {+                // if the next one's size is smaller, then insert+                // also insert if the next one's size is equal, but it joined the queue later+                if( ((*elig_itr)->Players.size()<size) ||+                    ((*elig_itr)->Players.size() == size && (*elig_itr)->JoinTime > jointime) )+                {+                    insert(elig_itr,(*itr));+                    inserted = true;+                    break;+                }+            }+            // if not inserted -> this is the smallest group -> push_back+            if(!inserted)+            {+                push_back((*itr));+            }+        }+    }+}++// remove group from eligible groups+// used when building selection pools+void BattleGroundQueue::EligibleGroups::RemoveGroup(GroupQueueInfo * ginfo)+{+    for(std::list<GroupQueueInfo *>::iterator itr = begin(); itr != end(); ++itr)+    {+        if((*itr)==ginfo)+        {+            erase(itr);+            return;+        }+    }+}++// selection pool initialization, used to clean up from prev selection+void BattleGroundQueue::SelectionPool::Init()+{+    SelectedGroups.clear();+    MaxGroup = 0;+    PlayerCount = 0;+}++// get the maximal group from the selection pool+// used when building the pool, and have to remove the largest+GroupQueueInfo * BattleGroundQueue::SelectionPool::GetMaximalGroup()+{+    if(SelectedGroups.empty())+    {+        sLog.outError("Getting max group when selection pool is empty, this should never happen.");+        MaxGroup = NULL;+        return 0;+    }+    // actually select the max group if it's not set+    if(MaxGroup==0 && !SelectedGroups.empty())+    {+        uint32 max_size = 0;+        for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)+        {+            if(max_size<(*itr)->Players.size())+            {+                MaxGroup =(*itr);+                max_size = MaxGroup->Players.size();+            }+        }+    }+    return MaxGroup;+}++// remove group info from selection pool+// used when building selection pools and have to remove maximal group+void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)+{+    // uninitiate max group info if needed+    if(MaxGroup == ginfo)+        MaxGroup = 0;+    // find what to remove+    for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)+    {+        if((*itr)==ginfo)+        {+            SelectedGroups.erase(itr);+            // decrease selected players count+            PlayerCount -= ginfo->Players.size();+            return;+        }+    }+}++// add group to selection+// used when building selection pools+void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)+{+    SelectedGroups.push_back(ginfo);+    // increase selected players count+    PlayerCount+=ginfo->Players.size();+    if(!MaxGroup || ginfo->Players.size() > MaxGroup->Players.size())+    {+        // update max group info if needed+        MaxGroup = ginfo;+    }+}++// add group to bg queue with the given leader and bg specifications+GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating)+{+    uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel();++    // create new ginfo+    // cannot use the method like in addplayer, because that could modify an in-queue group's stats+    // (e.g. leader leaving queue then joining as individual again)+    GroupQueueInfo* ginfo = new GroupQueueInfo;+    ginfo->BgTypeId                  = BgTypeId;+    ginfo->ArenaType                 = ArenaType;+    ginfo->IsRated                   = isRated;+    ginfo->IsInvitedToBGInstanceGUID = 0;                       // maybe this should be modifiable by function arguments to enable selection of running instances?+    ginfo->JoinTime                  = getMSTime();+    ginfo->Team                      = leader->GetTeam();++    if(sBattleGroundMgr.GetMaxRatingDifference())               // if max difference is set, then store rating info for queue+        ginfo->ArenaTeamRating       = arenaRating;+    else+        ginfo->ArenaTeamRating       = 0;                       // don't if it doesn't matter++    ginfo->Players.clear();++    m_QueuedGroups[queue_id].push_back(ginfo);++    // return ginfo, because it is needed to add players to this group info+    return ginfo;+}++void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)+{     uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();      //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak     PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()];     info.InviteTime                 = 0;-    info.IsInvitedToBGInstanceGUID  = 0;     info.LastInviteTime             = 0;     info.LastOnlineTime             = getMSTime();-    info.Team                       = plr->GetTeam();+    info.GroupInfo                  = ginfo; -    //add player to waiting order queue-    m_PlayersSortedByWaitTime[queue_id].push_back(plr->GetGUID());--    if(plr->GetTeam() == ALLIANCE)-        m_QueuedPlayers[queue_id].Alliance++;-    else-        m_QueuedPlayers[queue_id].Horde++;--    /* temporary BG queue status message-    std::ostringstream str;-    str << "Battleground queue invited status: horde: " << m_QueuedPlayers[queue_id].Horde << ", aliance: " << m_QueuedPlayers[queue_id].Alliance;-    plr->Say(str.str(), LANG_UNIVERSAL);*/--    this->Update(bgTypeId, queue_id);+    // add the pinfo to ginfo's list+    ginfo->Players[plr->GetGUID()]  = &info; }  void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)@@ -93,11 +248,22 @@      uint32 queue_id = 0;     QueuedPlayersMap::iterator itr;+    GroupQueueInfo * group;+    QueuedGroupsList::iterator group_itr;     bool IsSet = false;-    if(!plr)-    {                                                       //player is offline, we need to find him somewhere in queues-        /// there is something wrong if this code is run, because we have in queue only online players!-        sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");+    if(plr)+    {+        queue_id = plr->GetBattleGroundQueueIdFromLevel();++        itr = m_QueuedPlayers[queue_id].find(guid);+        if(itr != m_QueuedPlayers[queue_id].end())+            IsSet = true;+    }++    if(!IsSet)+    {                                                       +        // either player is offline, or he levelled up to another queue category+        // sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");         for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)         {             itr = m_QueuedPlayers[i].find(guid);@@ -109,44 +275,228 @@             }         }     }-    else-    {                                                       //player is online, we have his level, so we can find exact queue from his level-        queue_id = plr->GetBattleGroundQueueIdFromLevel();-        itr = m_QueuedPlayers[queue_id].find(guid);-        IsSet = true;++    // couldn't find the player in bg queue, return+    if(!IsSet)+    {+        sLog.outError("Battleground: couldn't find player to remove.");+        return;     } -    //all variables are set, so remove player-    //remove player from time queue-    m_PlayersSortedByWaitTime[queue_id].remove(guid);+    group = itr->second.GroupInfo; -    if (IsSet && itr != m_QueuedPlayers[queue_id].end())+    for(group_itr=m_QueuedGroups[queue_id].begin(); group_itr != m_QueuedGroups[queue_id].end(); ++group_itr)     {-        if (!itr->second.IsInvitedToBGInstanceGUID)+        if(group == (GroupQueueInfo*)(*group_itr))+            break;+    }++    // variables are set (what about leveling up when in queue????)+    // remove player from group+    // if only player there, remove group++    // remove player queue info from group queue info+    std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);++    if(pitr != group->Players.end())+        group->Players.erase(pitr);++    // check for iterator correctness+    if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())+    {+        // used when player left the queue, NOT used when porting to bg+        if (decreaseInvitedCount)         {-            if(itr->second.Team == ALLIANCE)-                m_QueuedPlayers[queue_id].Alliance--;-            else-                m_QueuedPlayers[queue_id].Horde--;-        }-        else-        {-            if (decreaseInvitedCount)+            // if invited to bg, and should decrease invited count, then do it+            if(group->IsInvitedToBGInstanceGUID)             {-                BattleGround* bg = sBattleGroundMgr.GetBattleGround(itr->second.IsInvitedToBGInstanceGUID);+                BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID);                 if (bg)-                    bg->DecreaseInvitedCount(itr->second.Team);+                    bg->DecreaseInvitedCount(group->Team);+                if (!bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE))+                {+                    // no more players on battleground, set delete it+                    bg->SetDeleteThis();+                }             }+            // update the join queue, maybe now the player's group fits in a queue!+            // not yet implemented (should store bgTypeId in group queue info?)         }+        // remove player queue info         m_QueuedPlayers[queue_id].erase(itr);+        // remove group queue info if needed+        if(group->Players.empty())+        {+            m_QueuedGroups[queue_id].erase(group_itr);+            delete group;+        }     } } +bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)+{+    // set side if needed+    if(side)+        ginfo->Team = side;++    if(!ginfo->IsInvitedToBGInstanceGUID)+    {+        // not yet invited+        // set invitation+        ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();+        uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());+        // loop through the players+        for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)+        {+            // set status+            itr->second->InviteTime = getMSTime();+            itr->second->LastInviteTime = getMSTime();++            // get the player+            Player* plr = objmgr.GetPlayer(itr->first);+            // if offline, skip him+            if(!plr)+                continue;++            // invite the player+            sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team);++            WorldPacket data;++            uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);++            sLog.outDebug("Battleground: invite plr %u queueindex %u bgtype %u",plr->GetGUIDLow(),queueSlot,bg->GetTypeID());++            // send status packet+            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, side?side:plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);+            plr->GetSession()->SendPacket(&data);+        }+        return true;+    }++    return false;+}++// this function is responsible for the selection of queued groups when trying to create new battlegrounds+bool BattleGroundQueue::BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers,  SelectionPoolBuildMode mode, uint8 ArenaType, bool isRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime)+{+    uint32 side;+    switch(mode)+    {+    case NORMAL_ALLIANCE:+    case ONESIDE_ALLIANCE_TEAM1:+    case ONESIDE_ALLIANCE_TEAM2:+        side = ALLIANCE;+        break;+    case NORMAL_HORDE:+    case ONESIDE_HORDE_TEAM1:+    case ONESIDE_HORDE_TEAM2:+        side = HORDE;+        break;+    default:+        //unknown mode, return false+        sLog.outDebug("Battleground: unknown selection pool build mode, returning...");+        return false;+        break;+    }++    // inititate the groups eligible to create the bg+    m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime);+    // init the selected groups (clear)+    m_SelectionPools[mode].Init();+    while(!(m_EligibleGroups.empty()))+    {+        sLog.outDebug("m_EligibleGroups is not empty, continue building selection pool");+        // in decreasing group size, add groups to join if they fit in the MaxPlayersPerTeam players+        for(EligibleGroups::iterator itr= m_EligibleGroups.begin(); itr!=m_EligibleGroups.end(); ++itr)+        {+            // get the maximal not yet checked group+            GroupQueueInfo * MaxGroup = (*itr);+            // if it fits in the maxplayer size, add it+            if( (m_SelectionPools[mode].GetPlayerCount() + MaxGroup->Players.size()) <= MaxPlayers )+            {+                m_SelectionPools[mode].AddGroup(MaxGroup);+            }+        }+        if(m_SelectionPools[mode].GetPlayerCount()>=MinPlayers)+        {+            // the selection pool is set, return+            sLog.outDebug("pool build succeeded, return true");+            return true;+        }+        // if the selection pool's not set, then remove the group with the highest player count, and try again with the rest.+        GroupQueueInfo * MaxGroup = m_SelectionPools[mode].GetMaximalGroup();+        m_EligibleGroups.RemoveGroup(MaxGroup);+        m_SelectionPools[mode].RemoveGroup(MaxGroup);+    }+    // failed to build a selection pool matching the given values+    return false;+}++// used to remove the Enter Battle window if the battle has already, but someone still has it+// (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event+void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)+{+    uint32 queue_id = bg->GetQueueType();+    uint32 bgInstanceId = bg->GetInstanceID();+    uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());+    QueuedGroupsList::iterator itr, next;+    for(itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next)+    {+        // must do this way, because the groupinfo will be deleted when all playerinfos are removed+        GroupQueueInfo * ginfo = (*itr);+        next = itr;+        ++next;+        // if group was invited to this bg instance, then remove all references+        if(ginfo->IsInvitedToBGInstanceGUID == bgInstanceId)+        {+            // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop+            uint32 to_remove = ginfo->Players.size();+            uint32 team = ginfo->Team;+            for(int i = 0; i < to_remove; ++i)+            {+                // always remove the first one in the group+                std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();+                if(itr2 == ginfo->Players.end())+                {+                    sLog.outError("Empty Players in ginfo, this should never happen!");+                    return;+                }++                // get the player+                Player * plr = objmgr.GetPlayer(itr2->first);+                if(!plr)+                {+                    sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");+                    continue;+                }++                // get the queueslot+                uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);+                if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue+                {+                    plr->RemoveBattleGroundQueueId(bgQueueTypeId);+                    // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!+                    RemovePlayer(itr2->first, true);+                    // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups+                    // but updateing the queue can't hurt+                    Update(bgQueueTypeId, bg->GetQueueType());+                    // send info to client+                    WorldPacket data;+                    sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0);+                    plr->GetSession()->SendPacket(&data);+                }+            }+        }+    }+}+ /*-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-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+this method is called when group is inserted, or player / group is removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue+it must be called after fully adding the members of a group to ensure group joining+should be called after removeplayer functions in some cases */-void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id)+void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating) {     if (queue_id >= MAX_BATTLEGROUND_QUEUES)     {@@ -156,158 +506,300 @@     }      //if no players in queue ... do nothing-    if (this->m_QueuedPlayers[queue_id].Alliance == 0 && this->m_QueuedPlayers[queue_id].Horde == 0)+    if (this->m_QueuedGroups[queue_id].size() == 0)         return; +    uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);+     //battleground with free slot for player should be always the last in this queue-    BGFreeSlotQueueType::iterator itr;-    for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); ++itr)+    BGFreeSlotQueueType::iterator itr, next;+    for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)     {+        next = itr;+        ++next;         // battleground is running, so if:         // DO NOT allow queue manager to invite new player to running arena-        if ((*itr)->isBattleGround() && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)+        if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)         {             //we must check both teams             BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)             // and iterator is invalid -            //check if there are some players in queue-            if (m_QueuedPlayers[queue_id].Alliance > 0 || m_QueuedPlayers[queue_id].Horde > 0)+            for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr)             {-                for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();)+                // did the group join for this bg type?+                if((*itr)->BgTypeId != bgTypeId)+                    continue;+                // if so, check if fits in+                if(bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size())                 {-                    Player* plr = objmgr.GetPlayer(*itr2);-                    if (!plr)-                    {-                        //something is wrong!, kick player from queue-                        sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug");-                        uint64 oldval = *itr2;-                        itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);-                        this->RemovePlayer(oldval, true);-                        continue;-                    }+                    // if group fits in, invite it+                    InviteGroupToBG((*itr),bg,(*itr)->Team);+                }+            } -                    // player will be invited, if in bg there is a free slot for him-                    if (bg->HasFreeSlotsForTeam(plr->GetTeam()))-                    {-                        // iterator to player's queue status-                        QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2);+            if (!bg->HasFreeSlots())+            {+                //remove BG from BGFreeSlotQueue+                bg->RemoveFromBGFreeSlotQueue();+            }+        }+    } -                        // remove him from time queue-                        itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);+    // finished iterating through the bgs with free slots, maybe we need to create a new bg -                        // 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)-                        if (itrPlayerStatus == m_QueuedPlayers[queue_id].end())-                            continue;+    BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);+    if(!bg_template)+    {+        sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);+        return;+    } -                        // check if player is not already invited-                        if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)-                        {-                            itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg->GetInstanceID();-                            itrPlayerStatus->second.InviteTime = getMSTime();-                            itrPlayerStatus->second.LastInviteTime = getMSTime();-                            if(itrPlayerStatus->second.Team == ALLIANCE)-                                m_QueuedPlayers[queue_id].Alliance--;-                            else-                                m_QueuedPlayers[queue_id].Horde--;-                            sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID());+    // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)+    uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();+    uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();+    if(bg_template->isArena())+    {+        switch(arenatype)+        {+        case ARENA_TYPE_2v2:+            MaxPlayersPerTeam = 2;+            MinPlayersPerTeam = 2;+            break;+        case ARENA_TYPE_3v3:+            MaxPlayersPerTeam = 3;+            MinPlayersPerTeam = 3;+            break;+        case ARENA_TYPE_5v5:+            MaxPlayersPerTeam = 5;+            MinPlayersPerTeam = 5;+            break;+        }+    } -                            WorldPacket data;-                            uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId);-                            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);-                            plr->GetSession()->SendPacket(&data);-                        }-                    }-                    else-                        ++itr2;+    uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();+    uint32 arenaMaxRating = (arenaRating == 0)? 0 : arenaRating + sBattleGroundMgr.GetMaxRatingDifference();+    uint32 discardTime = 0;+    if(sBattleGroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattleGroundMgr.GetRatingDiscardTimer())+        discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer(); -                    //if battleground is FULL, then it is removed from free slot queue - not yet implemented!-                    if (!bg->HasFreeSlots())-                    {-                        //if bg is full, there is no need to invite other players, so break-                        break;-                        //remove BG from BGFreeSlotQueue - not used now, in this system we don't remove BGs from free queue-                        //bg->RemoveFromBGFreeSlotQueue() --- do not uncomment this - not yet implemented-                    }-                }+    // try to build the selection pools+    bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);+    if(bAllyOK)+        sLog.outDebug("Battleground: ally pool succesfully build");+    else+        sLog.outDebug("Battleground: ally pool wasn't created");+    bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);+    if(bHordeOK)+        sLog.outDebug("Battleground: horde pool succesfully built");+    else+        sLog.outDebug("Battleground: horde pool wasn't created");++    // if selection pools are ready, create the new bg+    if (bAllyOK && bHordeOK)+    {+        BattleGround * bg2 = 0;+        // special handling for arenas+        if(bg_template->isArena())+        {+            // Find a random arena, that can be created+            uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};+            uint32 arena_num = urand(0,2);+            if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&+                !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&+                !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )+            {+                sLog.outError("Battleground: couldn't create arena");+                return;             }++            // set the MaxPlayersPerTeam values based on arenatype+            // setting the min player values isn't needed, since we won't be using that value later on.+            switch(arenatype)+            {+            case ARENA_TYPE_2v2:+                bg2->SetMaxPlayersPerTeam(2);+                bg2->SetMaxPlayers(4);+                break;+            case ARENA_TYPE_3v3:+                bg2->SetMaxPlayersPerTeam(3);+                bg2->SetMaxPlayers(6);+                break;+            case ARENA_TYPE_5v5:+                bg2->SetMaxPlayersPerTeam(5);+                bg2->SetMaxPlayers(10);+                break;+            default:+                break;+            }         }-    }+        else+        {+            // create new battleground+            bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId);+        } -    /* THIS IS A CASE THAT IN QUEUE THERE IS ENOUGHT PLAYERS TO START NEW BG */-    //itr->end is the last BG - template, which is not already started!+        if(!bg2)+        {+            sLog.outError("Battleground: couldn't create bg %u",bgTypeId);+            return;+        } -    /* here will be a most of change, when we create battlegrounds instanciated */-    /* if (there is enought players to start new BG)-        Battleground* newbg = sBattleGroundMgr.CreateNewBattleGround(bgTypeId)-        - that function will use the COPY constructor on BattleGround class ( in bg manager we should have one battleground as a template-            (battleground template will be used only to create new BGs, it will be an instance of BG class, but it won't ever start) */--    /* folowing code is working with current Battleground system and it should be removed, when BGs will work like instances */-    BattleGround* bg2 = sBattleGroundMgr.GetBattleGround(bgTypeId);-    if (bg2->GetQueueType() != MAX_BATTLEGROUND_QUEUES || bg2->GetStatus() != STATUS_WAIT_QUEUE)-        return;-    if (m_QueuedPlayers[queue_id].Alliance >= bg2->GetMinPlayersPerTeam() && m_QueuedPlayers[queue_id].Horde >= bg2->GetMinPlayersPerTeam())-    {+        // start the joining of the bg         bg2->SetStatus(STATUS_WAIT_JOIN);         bg2->SetQueueType(queue_id);+        // initialize arena / rating info+        bg2->SetArenaType(arenatype);+        // set rating+        bg2->SetRated(isRated); -        for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();)+        std::list<GroupQueueInfo* >::iterator itr;++        // invite groups from horde selection pool+        for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr)         {-            Player* plr = objmgr.GetPlayer(*itr2);-            if (!plr)+            InviteGroupToBG((*itr),bg2,HORDE);+        }++        // invite groups from ally selection pools+        for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)+        {+            InviteGroupToBG((*itr),bg2,ALLIANCE);+        }++        // start the battleground+        bg2->StartBattleGround(0);+    }++    // there weren't enough players for a "normal" match+    // if arena, enable horde versus horde or alliance versus alliance teams here++    else if(bg_template->isArena())+    {+        bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false;+        bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false;+        bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);+        if(bOneSideHordeTeam1)+        {+            // one team has been selected, find out if other can be selected too+            std::list<GroupQueueInfo* >::iterator itr;+            // temporarily change the team side to enable building the next pool excluding the already selected groups+            for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)+                (*itr)->Team=ALLIANCE;++            bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);++            // change back the team to horde+            for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)+                (*itr)->Team=HORDE;++            if(!bOneSideHordeTeam2)+                bOneSideHordeTeam1 = false;+        }+        if(!bOneSideHordeTeam1)+        {+            // check for one sided ally+            bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);+            if(bOneSideAllyTeam1)             {-                //something is wrong!, kick player from queue-                sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug");-                uint64 oldval = *itr2;-                itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);-                this->RemovePlayer(oldval, true);-                continue;+                // one team has been selected, find out if other can be selected too+                std::list<GroupQueueInfo* >::iterator itr;+                // temporarily change the team side to enable building the next pool excluding the already selected groups+                for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)+                    (*itr)->Team=HORDE;++                bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);++                // change back the team to ally+                for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)+                    (*itr)->Team=ALLIANCE;             } -            /* TODO: (i'm not sure this code will be useful:-            here should be some condition like if (bg2->isArena() && bg2->isRated())+            if(!bOneSideAllyTeam2)+                bOneSideAllyTeam1 = false;+        }+        // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!+        if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) ||+            (bOneSideAllyTeam1 && bOneSideAllyTeam2) )+        {+            // create random arena+            uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};+            uint32 arena_num = urand(0,2);+            BattleGround* bg2 = NULL;+            if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&+                !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&+                !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )             {-                invite players from 1 certain group on each faction to play arena match-            } else if ....and existing code-            */-            // player will be invited, if in bg there is a free slot for him-            if (bg2->HasFreeSlotsForTeam(plr->GetTeam()))+                sLog.outError("Could not create arena.");+                return;+            }++            sLog.outDebug("Arena created.");+            // init stats+            switch(arenatype)             {-                // iterator to player's queue status-                QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2);+            case ARENA_TYPE_2v2:+                bg2->SetMaxPlayersPerTeam(2);+                bg2->SetMaxPlayers(4);+                break;+            case ARENA_TYPE_3v3:+                bg2->SetMaxPlayersPerTeam(3);+                bg2->SetMaxPlayers(6);+                break;+            case ARENA_TYPE_5v5:+                bg2->SetMaxPlayersPerTeam(5);+                bg2->SetMaxPlayers(10);+                break;+            default:+                break;+            } -                // remove him from time queue-                itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);+            bg2->SetRated(isRated);+            // which side has enough players?+            uint32 side = 0;+            SelectionPoolBuildMode mode1, mode2;+            // find out what pools are we using+            if(bOneSideAllyTeam1 && bOneSideAllyTeam2)+            {+                side = ALLIANCE;+                mode1 = ONESIDE_ALLIANCE_TEAM1;+                mode2 = ONESIDE_ALLIANCE_TEAM2;+            }+            else+            {+                side = HORDE;+                mode1 = ONESIDE_HORDE_TEAM1;+                mode2 = ONESIDE_HORDE_TEAM2;+            }+            // assigned team of the other group+            uint32 other_side;+            if(side == ALLIANCE)+                other_side = HORDE;+            else+                other_side = ALLIANCE; -                // 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)-                if (itrPlayerStatus == m_QueuedPlayers[queue_id].end())-                    continue;+            // start the joining of the bg+            bg2->SetStatus(STATUS_WAIT_JOIN);+            bg2->SetQueueType(queue_id);+            // initialize arena / rating info+            bg2->SetArenaType(arenatype); -                //check if player is not already invited-                if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)-                {-                    itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg2->GetInstanceID();-                    itrPlayerStatus->second.InviteTime = getMSTime();-                    itrPlayerStatus->second.LastInviteTime = getMSTime();+            std::list<GroupQueueInfo* >::iterator itr; -                    if(itrPlayerStatus->second.Team == ALLIANCE)-                        m_QueuedPlayers[queue_id].Alliance--;-                    else-                        m_QueuedPlayers[queue_id].Horde--;+            // invite players from the first group as horde players (actually green team)+            for(itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr)+            {+                InviteGroupToBG((*itr),bg2,HORDE);+            } -                    sBattleGroundMgr.InvitePlayer(plr, bg2->GetInstanceID());+            // invite players from the second group as ally players (actually gold team)+            for(itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr)+            {+                InviteGroupToBG((*itr),bg2,ALLIANCE);+            } -                    WorldPacket data;-                    uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId);-                    sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);-                    plr->GetSession()->SendPacket(&data);-                }-            }-            else-                ++itr2;+            bg2->StartBattleGround(0);         }-        bg2->StartBattleGround(0);     } } @@ -330,16 +822,17 @@     BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);     if (bg)     {-        uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());+        uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());+        uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);         if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue         {             // 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-            BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];+            BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];             BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);-            if (qItr != qpMap.end() && qItr->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID)+            if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)             {                 WorldPacket data;-                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, BG_REMIND_INVITE_TIME, 0);+                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, BG_REMIND_INVITE_TIME, 0);                 plr->GetSession()->SendPacket(&data);             }         }@@ -366,17 +859,18 @@     BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);     if (bg)     {-        uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());+        uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());+        uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);         if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue         {             // 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-            if (sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid)->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID)+            if (sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid)->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)             {-                plr->RemoveBattleGroundQueueId(bg->GetTypeID());-                sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].RemovePlayer(m_PlayerGuid, true);-                sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].Update(bg->GetTypeID(), bg->GetQueueType());+                plr->RemoveBattleGroundQueueId(bgQueueTypeId);+                sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);+                sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgQueueTypeId, bg->GetQueueType());                 WorldPacket data;-                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_NONE, 0, 0);+                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0);                 plr->GetSession()->SendPacket(&data);             }         }@@ -398,22 +892,78 @@ BattleGroundMgr::BattleGroundMgr() {     m_BattleGrounds.clear();+    m_AutoDistributePoints = (bool)sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS);+    m_MaxRatingDifference = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);+    m_RatingDiscardTimer = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);+    m_NextRatingDiscardUpdate = m_RatingDiscardTimer;+    m_AutoDistributionTimeChecker = 0; }  BattleGroundMgr::~BattleGroundMgr() {-    for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)-        delete itr->second;+    BattleGroundSet::iterator itr, next;+    for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)+    {+        next = itr;+        ++next;+        BattleGround * bg = itr->second;+        m_BattleGrounds.erase(itr);+        delete bg;+    }     m_BattleGrounds.clear(); } +// used to update running battlegrounds, and delete finished ones void BattleGroundMgr::Update(time_t diff) {-    for(BattleGroundSet::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)+    BattleGroundSet::iterator itr, next;+    for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)+    {+        next = itr;+        ++next;         itr->second->Update(diff);+        // use the SetDeleteThis variable+        // direct deletion caused crashes+        if(itr->second->m_SetDeleteThis)+        {+            BattleGround * bg = itr->second;+            m_BattleGrounds.erase(itr);+            delete bg;+        }+    }+    // if rating difference counts, maybe force-update queues+    if(m_MaxRatingDifference)+    {+        // it's time to force update+        if(m_NextRatingDiscardUpdate < diff)+        {+            // forced update for level 70 rated arenas+            m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA,6,ARENA_TYPE_2v2,true,0);+            m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA,6,ARENA_TYPE_3v3,true,0);+            m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA,6,ARENA_TYPE_5v5,true,0);+            m_NextRatingDiscardUpdate = m_RatingDiscardTimer;+        } +        else +            m_NextRatingDiscardUpdate -= diff;+    }+    if(m_AutoDistributePoints)+    {+        if(m_AutoDistributionTimeChecker < diff)+        {+            if(time(NULL) > m_NextAutoDistributionTime)+            {+                DistributeArenaPoints();+                m_NextAutoDistributionTime = time(NULL) + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_WEEK;+                CharacterDatabase.PExecute("UPDATE `saved_variables` SET `NextArenaPointDistributionTime` = FROM_UNIXTIME('"I64FMTD"')",(uint64)m_NextAutoDistributionTime);+            }+            m_AutoDistributionTimeChecker = 600000; // check 10 minutes+        }+        else+            m_AutoDistributionTimeChecker -= diff;+    } } -void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2)+void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted) {     // we can be in 3 queues in same time...     if(StatusID == 0)@@ -427,7 +977,7 @@      data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));     *data << uint32(QueueSlot);                             // queue id (0...2) - player can be in 3 queues in time-    *data << uint8(bg->GetArenaType());                     // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas+    *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!!!!     switch(bg->GetTypeID())                                 // value depends on bg id     {         case BATTLEGROUND_AV:@@ -460,9 +1010,9 @@     }      if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))-        *data << uint32(BATTLEGROUND_AA);                   // all arenas+        *data << uint32(BATTLEGROUND_AA);                   // all arenas   I don't think so.     else-        *data << uint32(bg->GetTypeID());                   // BG id from DBC+    *data << uint32(bg->GetTypeID());                   // BG id from DBC      *data << uint16(0x1F90);                                // unk value 8080     *data << uint32(bg->GetInstanceID());                   // instance id@@ -470,7 +1020,7 @@     if(bg->isBattleGround())         *data << uint8(bg->GetTeamIndexByTeamId(team));     // team     else-        *data << uint8(bg->isRated());                      // is rated battle+        *data << uint8(israted?israted:bg->isRated());                      // is rated battle      *data << uint32(StatusID);                              // status     switch(StatusID)@@ -505,7 +1055,7 @@     {         for(uint8 i = 0; i < 2; i++)         {-            *data << uint32(3000+1+i);                      // rating change: showed value - 3000+            *data << uint32(3000+bg->m_ArenaTeamRatingChanges[i]);                      // rating change: showed value - 3000             *data << uint8(0);                              // string         }     }@@ -536,11 +1086,13 @@         {             // that part probably wrong             Player *plr = objmgr.GetPlayer(itr->first);+            uint32 team = bg->GetPlayerTeam(plr->GetGUID());+            if(!team) team = plr->GetTeam();             if(plr)             {-                if(plr->GetTeam() == HORDE)+                if(team == HORDE)                     *data << uint8(0);-                else if(plr->GetTeam() == ALLIANCE)+                else if(team == ALLIANCE)                     *data << uint8(1);                 else                     *data << uint8(0);@@ -624,20 +1176,133 @@     *data << uint64(plr->GetGUID()); } -void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID)+void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team) {     // set invited player counters:     BattleGround* bg = this->GetBattleGround(bgInstanceGUID);-    bg->IncreaseInvitedCount(plr->GetTeam());+    bg->IncreaseInvitedCount(team); +    // set the arena teams for rated matches+    if(bg->isArena() && bg->isRated())+    {+        switch(bg->GetArenaType())+        {+        case ARENA_TYPE_2v2:+            bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));+            break;+        case ARENA_TYPE_3v3:+            bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));+            break;+        case ARENA_TYPE_5v5:+            bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));+            break;+        default:+            break;+        }+    }+     // create invite events:     //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     BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID);     plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(BG_REMIND_INVITE_TIME));-    BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, plr->GetTeam());+    BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team);     plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(2*BG_REMIND_INVITE_TIME)); } +BattleGround * BattleGroundMgr::GetBattleGroundTemplate(uint32 bgTypeId)+{+    return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();+}++// create a new battleground that will really be used to play+BattleGround * BattleGroundMgr::CreateNewBattleGround(uint32 bgTypeId)+{+    BattleGround *bg = NULL;++    // get the template BG+    BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);++    if(!bg_template)+    {+        sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);+        return 0;+    }+    +    // create a copy of the BG template+    switch(bgTypeId)+    {+        case BATTLEGROUND_AV: +            bg = new BattleGroundAV(*(BattleGroundAV*)bg_template); +            break;+        case BATTLEGROUND_WS: +            bg = new BattleGroundWS(*(BattleGroundWS*)bg_template); +            break;+        case BATTLEGROUND_AB: +            bg = new BattleGroundAB(*(BattleGroundAB*)bg_template); +            break;+        case BATTLEGROUND_NA: +            bg = new BattleGroundNA(*(BattleGroundNA*)bg_template); +            break;+        case BATTLEGROUND_BE: +            bg = new BattleGroundBE(*(BattleGroundBE*)bg_template); +            break;+        case BATTLEGROUND_AA: +            bg = new BattleGroundAA(*(BattleGroundAA*)bg_template); +            break;+        case BATTLEGROUND_EY: +            bg = new BattleGroundEY(*(BattleGroundEY*)bg_template); +            break;+        case BATTLEGROUND_RL: +            bg = new BattleGroundRL(*(BattleGroundRL*)bg_template); +            break;+        default:+            //bg = new BattleGround;   +            return 0;+            break;             // placeholder for non implemented BG+    }++    // generate a new instance id+    bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id++/*  UNCOMMENT THIS IF MAP SYSTEM IS UPDATED+    // get the map+    Map * m = MapManager::Instance().GetMap(bg->GetMapId(),NULL);+    if(!m)+    {+        // no map found, delete bg and return null+        delete bg;+        return 0;+    }++    // create new instance if the map is instanceable+    if(m->Instanceable())+    {+        // generate a new instance id+        bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id+        ((MapInstanced*)m)->CreateInstance(bg->GetInstanceID(),m);+    }+*/++    // reset the new bg (set status to status_wait_queue from status_none)+    bg->Reset();++    if(!(bg->SetupBattleGround()))+    {+        sLog.outError("BattleGround: CreateNewBattleGround: SetupBattleGround failed for bg %u", bgTypeId);+        delete bg;+        return 0;+    }++    // add BG to free slot queue+    bg->AddToBGFreeSlotQueue();++    // add bg to update list+    AddBattleGround(bg->GetInstanceID(), bg);++    return bg;+}++// used to create the BG templates uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO) {     // Create the BG@@ -657,12 +1322,12 @@     }      bg->SetMapId(MapID);++    // set unloadflag to false+    Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(MapID));+    if(map) map->SetUnloadMap(false);+     bg->Reset();-    if(!bg->SetupBattleGround())-    {-        delete bg;-        return 0;-    }      BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId);     //in previous method is checked if exists entry in sBattlemasterListStore, so no check needed@@ -672,7 +1337,7 @@     }      bg->SetTypeID(bgTypeId);-    bg->SetInstanceID(bgTypeId);                               // temporary+    bg->SetInstanceID(0);                               // template bg, instance id is 0     bg->SetMinPlayersPerTeam(MinPlayersPerTeam);     bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);     bg->SetMinPlayers(MinPlayersPerTeam*2);@@ -681,12 +1346,14 @@     bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);     bg->SetTeamStartLoc(HORDE,    Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);     bg->SetLevelRange(LevelMin, LevelMax);-    //add BaggleGround instance to FreeSlotQueue++    //add BattleGround instance to FreeSlotQueue (.back() will return the template!)     bg->AddToBGFreeSlotQueue(); -    AddBattleGround(bg->GetInstanceID(), bg);-    //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);-    return bg->GetInstanceID();+    // do NOT add to update list, since this is a template battleground!++    // return some not-null value, bgTypeId is good enough for me+    return bgTypeId;  }  void BattleGroundMgr::CreateInitialBattleGrounds()@@ -806,6 +1473,86 @@     sLog.outString( ">> Loaded %u battlegrounds", count ); } +void BattleGroundMgr::InitAutomaticArenaPointDistribution()+{+    if(m_AutoDistributePoints)+    {+        sLog.outDebug("Initializing Automatic Arena Point Distribution");+        QueryResult * result = CharacterDatabase.Query("SELECT UNIX_TIMESTAMP(`NextArenaPointDistributionTime`) FROM `saved_variables`");+        if(!result)+        {+            sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now."); +            m_NextAutoDistributionTime = time(NULL) + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_WEEK;+            CharacterDatabase.PExecute("INSERT INTO `saved_variables` (`NextArenaPointDistributionTime`) VALUES ( FROM_UNIXTIME('"I64FMTD"') )",(uint64)m_NextAutoDistributionTime);+        }+        else+        {+            m_NextAutoDistributionTime = (*result)[0].GetUInt64();+            delete result;+        }+        sLog.outDebug("Automatic Arena Point Distribution initialized.");+    }+}++void BattleGroundMgr::DistributeArenaPoints()+{+    // used to distribute arena points based on last week's stats+    sWorld.SendWorldText("Flushing Arena points based on team ratings, this may take a few minutes. Please stand by...", NULL);++    sWorld.SendWorldText("Distributing arena points to online players...", NULL);++    //TODO: Guard Player map+    HashMapHolder<Player>::MapType& m = ObjectAccessor::Instance().GetPlayers();+    for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)+    {+        uint64 guid = itr->second->GetGUID();+        Player * pl = itr->second;+        if(!pl)+            continue;+        uint32 mod = 0;+        for(int i=0; i<3; ++i)+        {+            ArenaTeam * at = objmgr.GetArenaTeamById(pl->GetArenaTeamId(i));+            if(at && mod < at->GetMemberPoints(guid))+                mod = at->GetMemberPoints(guid);+            // reset weekly played match count for team+            if(at)+                pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * at->GetSlot() + 2, 0);++        }+        mod += pl->GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY);+        if(mod > 5000)+            mod = 5000;++        pl->SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, mod);++        CharacterDatabase.PExecute("UPDATE `arena_team_member` SET `points_to_add` = '0' WHERE `guid` = '%u'",guid);+    }++    sWorld.SendWorldText("Finished distributing arena points to online players. Now saving... ", NULL);++    ObjectAccessor::Instance().SaveAllPlayers();++    sWorld.SendWorldText("Online players saved.", NULL);++    sWorld.SendWorldText("Distributing arena points to offline players...", NULL);++    CharacterDatabase.BeginTransaction();+    CharacterDatabase.PExecute("UPDATE `character` 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`) ) < '5000'), 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`), '5000') 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, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY+1, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY+1);+    for(int i=0; i<3; ++i)+    {+        // reset weekly played matches+        uint32 position = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * i + 2;+        CharacterDatabase.PExecute("UPDATE `character` SET `data` = CONCAT( SUBSTRING_INDEX(`data`,' ','%u'),' ','0',' ',SUBSTRING(`data` FROM (CHAR_LENGTH(SUBSTRING_INDEX(`data`,' ','%u')) + 2)))",position, position + 1);+    }+    CharacterDatabase.Execute("UPDATE `arena_team_member` SET `points_to_add` = '0', `played_week` = '0', `wons_week` = '0'");+    CharacterDatabase.Execute("UPDATE `arena_team_stats` SET `games` = '0', `wins` = '0'");+    CharacterDatabase.CommitTransaction();++    sWorld.SendWorldText("Finished distributing arena points to offline players.", NULL);+    sWorld.SendWorldText("Done flushing Arena points.", NULL);+}+ void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player* plr, uint32 bgTypeId) {     uint32 PlayerLevel = 10;@@ -841,18 +1588,27 @@     } } -void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 bgTypeId)+void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, uint32 team) {-    BattleGround *bg = GetBattleGround(bgTypeId);+    BattleGround *bg = GetBattleGround(instanceId);     if(bg)     {         uint32 mapid = bg->GetMapId();         float x, y, z, O;-        bg->GetTeamStartLoc(pl->GetTeam(), x, y, z, O);+        if(team==0)+            team = pl->GetTeam();+        bg->GetTeamStartLoc(team, x, y, z, O);          sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);-        pl->TeleportTo(mapid, x, y, z, O);+        pl->SetInstanceId(instanceId); +        pl->m_BoundInstances[mapid]=std::pair<uint32,uint32>(instanceId, pl->GetGUIDLow());+        // teleport as gm command+        pl->TeleportTo(mapid, x, y, z, O, true, true, false, true);     }+    else+    {+        sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);+    } }  void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid)@@ -864,3 +1620,91 @@     data << guid << time_;     pl->GetSession()->SendPacket(&data); }++void BattleGroundMgr::RemoveBattleGround(uint32 instanceID)+{+    BattleGroundSet::iterator itr = m_BattleGrounds.find(instanceID);+    if(itr!=m_BattleGrounds.end())+        m_BattleGrounds.erase(itr);+}++bool BattleGroundMgr::IsArenaType(uint32 bgTypeId) const+{+    return ( bgTypeId == BATTLEGROUND_AA ||+        bgTypeId == BATTLEGROUND_BE ||+        bgTypeId == BATTLEGROUND_NA ||+        bgTypeId == BATTLEGROUND_RL );+}++bool BattleGroundMgr::IsBattleGroundType(uint32 bgTypeId) const+{+    return !IsArenaType(bgTypeId);+}++uint32 BattleGroundMgr::BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const+{+    switch(bgTypeId)+    {+    case BATTLEGROUND_WS:+        return BATTLEGROUND_QUEUE_WS;+    case BATTLEGROUND_AB:+        return BATTLEGROUND_QUEUE_AB;+    case BATTLEGROUND_AV:+        return BATTLEGROUND_QUEUE_AV;+    case BATTLEGROUND_EY:+        return BATTLEGROUND_QUEUE_EY;+    case BATTLEGROUND_AA:+    case BATTLEGROUND_NA:+    case BATTLEGROUND_RL:+    case BATTLEGROUND_BE:+        switch(arenaType)+        {+        case ARENA_TYPE_2v2:+            return BATTLEGROUND_QUEUE_2v2;+        case ARENA_TYPE_3v3:+            return BATTLEGROUND_QUEUE_3v3;+        case ARENA_TYPE_5v5:+            return BATTLEGROUND_QUEUE_5v5;+        default:+            return 0;+        }+    default:+        return 0;+    }+}++uint32 BattleGroundMgr::BGTemplateId(uint32 bgQueueTypeId) const+{+    switch(bgQueueTypeId)+    {+    case BATTLEGROUND_QUEUE_WS:+        return BATTLEGROUND_WS;+    case BATTLEGROUND_QUEUE_AB:+        return BATTLEGROUND_AB;+    case BATTLEGROUND_QUEUE_AV:+        return BATTLEGROUND_AV;+    case BATTLEGROUND_QUEUE_EY:+        return BATTLEGROUND_EY;+    case BATTLEGROUND_QUEUE_2v2:+    case BATTLEGROUND_QUEUE_3v3:+    case BATTLEGROUND_QUEUE_5v5:+        return BATTLEGROUND_AA;+    default:+        return 0;+    }+}++uint8 BattleGroundMgr::BGArenaType(uint32 bgQueueTypeId) const+{+    switch(bgQueueTypeId)+    {+    case BATTLEGROUND_QUEUE_2v2:+        return ARENA_TYPE_2v2;+    case BATTLEGROUND_QUEUE_3v3:+        return ARENA_TYPE_3v3;+    case BATTLEGROUND_QUEUE_5v5:+        return ARENA_TYPE_5v5;+    default:+        return 0;+    }+}Index: src/game/BattleGroundMgr.h===================================================================--- src/game/BattleGroundMgr.h	(revision 5306)+++ src/game/BattleGroundMgr.h	(working copy)@@ -34,53 +34,99 @@  #define MAX_BATTLEGROUND_TYPES 9                            // each BG type will be in array +#define MAX_BATTLEGROUND_QUEUE_TYPES 8+ #define BG_REMIND_INVITE_TIME 60000                         // when this time pass, player get invitation request again -struct PlayerQueueInfo+#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_WEEK    604800     // seconds in a week++struct GroupQueueInfo;                                      // type predefinition+struct PlayerQueueInfo                                      // stores information for players in queue {     uint32  InviteTime;                                     // first invite time     uint32  LastInviteTime;                                 // last invite time-    uint32  IsInvitedToBGInstanceGUID;                      // was invited to certain BG     uint32  LastOnlineTime;                                 // for tracking and removing offline players from queue after 5 minutes-    uint32  Team;                                           // Player team (ALLIANCE/HORDE)-    bool IsRated;-    bool AsGroup;                                           // uint32 GroupId;-    uint8 ArenaType;+    GroupQueueInfo * GroupInfo;                             // pointer to the associated groupqueueinfo }; -struct PlayersCount+struct GroupQueueInfo                                       // stores information about the group in queue (also used when joined as solo!) {-    uint32 Alliance;-    uint32 Horde;+    std::map<uint64, PlayerQueueInfo*> Players;             // player queue info map+    uint32  Team;                                           // Player team (ALLIANCE/HORDE)+    bool    IsRated;                                        // rated+    uint32  BgTypeId;                                       // battleground type id+    uint8   ArenaType;                                      // 2v2, 3v3, 5v5 or 0 when BG+    uint32  JoinTime;                                       // time when group was added+    uint32  IsInvitedToBGInstanceGUID;                      // was invited to certain BG+    uint32  ArenaTeamRating;                                // if rated match, inited to the rating of the team }; -template<class _Kty, class _Ty> class bgqueue: public std::map<_Kty, _Ty>-{-    public:-        uint32 Alliance;-        uint32 Horde;-        //bool   Ready; // not used now-        //uint32 AverageTime; //not already implemented (it should be average time in queue for last 10 players)-};-+class BattleGround; class BattleGroundQueue {     public:         BattleGroundQueue();         ~BattleGroundQueue();-/*-        uint32 GetType();-        void SetType(uint32 type);*/ -        void Update(uint32 bgTypeId, uint32 queue_id);+        void Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype = 0, bool isRated = false, uint32 minRating = 0); -        void AddPlayer(Player *plr, uint32 bgTypeId);+        GroupQueueInfo * AddGroup(Player * leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 ArenaRating);+        void AddPlayer(Player *plr, GroupQueueInfo * ginfo);         void RemovePlayer(uint64 guid, bool decreaseInvitedCount);+        void DecreaseGroupLength(uint32 queueId, uint32 AsGroup);+        void BGEndedRemoveInvites(BattleGround * bg); -        typedef bgqueue<uint64, PlayerQueueInfo> QueuedPlayersMap;+        typedef std::map<uint64, PlayerQueueInfo> QueuedPlayersMap;         QueuedPlayersMap m_QueuedPlayers[MAX_BATTLEGROUND_QUEUES];-        typedef std::list<uint64> PlayerGuidsSortedByTimeQueue;-        PlayerGuidsSortedByTimeQueue m_PlayersSortedByWaitTime[MAX_BATTLEGROUND_QUEUES];++        typedef std::list<GroupQueueInfo*> QueuedGroupsList;+        QueuedGroupsList m_QueuedGroups[MAX_BATTLEGROUND_QUEUES];++        // class to hold pointers to the groups eligible for a specific selection pool building mode+        class EligibleGroups : public std::list<GroupQueueInfo *>+        {+        public:+            void Init(QueuedGroupsList * source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType = 0, bool IsRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0);+            void RemoveGroup(GroupQueueInfo * ginfo);+        };++        EligibleGroups m_EligibleGroups;++        // class to select and invite groups to bg+        class SelectionPool+        {+        public:+            void Init();+            void AddGroup(GroupQueueInfo * group);+            GroupQueueInfo * GetMaximalGroup();+            void RemoveGroup(GroupQueueInfo * group);+            uint32 GetPlayerCount() const {return PlayerCount;}+        public:+            std::list<GroupQueueInfo *> SelectedGroups;+        private:+            uint32 PlayerCount;+            GroupQueueInfo * MaxGroup;+        };++        enum SelectionPoolBuildMode+        {+            NORMAL_ALLIANCE,+            NORMAL_HORDE,+            ONESIDE_ALLIANCE_TEAM1,+            ONESIDE_ALLIANCE_TEAM2,+            ONESIDE_HORDE_TEAM1,+            ONESIDE_HORDE_TEAM2,++            NUM_SELECTION_POOL_TYPES+        };++        SelectionPool m_SelectionPools[NUM_SELECTION_POOL_TYPES];++        bool BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType = 0, bool isRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0);++    private:++        bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side); };  /*@@ -98,7 +144,6 @@     private:         uint64 m_PlayerGuid;         uint32 m_BgInstanceGUID;- };  /*@@ -118,7 +163,6 @@         uint32 m_PlayersTeam; }; - class BattleGroundMgr {     public:@@ -134,18 +178,18 @@         void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, uint32 bgTypeId);         void BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value);         void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg);-        void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2);+        void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0, uint8 israted = 0);         void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid);          /* Player invitation */         // called from Queue update, or from Addplayer to queue-        void InvitePlayer(Player* plr, uint32 bgInstanceGUID);+        void InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team);          /* Battlegrounds */         BattleGroundSet::iterator GetBattleGroundsBegin() { return m_BattleGrounds.begin(); };         BattleGroundSet::iterator GetBattleGroundsEnd() { return m_BattleGrounds.end(); }; -        BattleGround* GetBattleGround(uint8 ID)+        BattleGround* GetBattleGround(uint32 ID)         {             BattleGroundSet::iterator i = m_BattleGrounds.find(ID);             if(i != m_BattleGrounds.end())@@ -154,26 +198,48 @@                 return NULL;         }; +        BattleGround * GetBattleGroundTemplate(uint32 bgTypeId);+        BattleGround * CreateNewBattleGround(uint32 bgTypeId);+         uint32 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);          inline void AddBattleGround(uint32 ID, BattleGround* BG) { m_BattleGrounds[ID] = BG; };+        void RemoveBattleGround(uint32 instanceID);          void CreateInitialBattleGrounds(); -        void SendToBattleGround(Player *pl, uint32 bgTypeId);+        void SendToBattleGround(Player *pl, uint32 bgTypeId, uint32 team = 0);          /* Battleground queues */         //these queues are instantiated when creating BattlegroundMrg-        BattleGroundQueue m_BattleGroundQueues[MAX_BATTLEGROUND_TYPES]; // public, because we need to access them in BG handler code+        BattleGroundQueue m_BattleGroundQueues[MAX_BATTLEGROUND_QUEUE_TYPES]; // public, because we need to access them in BG handler code          BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPES];          void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid); +        bool IsArenaType(uint32 bgTypeId) const;+        bool IsBattleGroundType(uint32 bgTypeId) const;+        uint32 BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const;+        uint32 BGTemplateId(uint32 bgQueueTypeId) const;+        uint8 BGArenaType(uint32 bgQueueTypeId) const;++        uint32 GetMaxRatingDifference() const {return m_MaxRatingDifference;}+        uint32 GetRatingDiscardTimer() const {return m_RatingDiscardTimer;}++        void InitAutomaticArenaPointDistribution();+        void DistributeArenaPoints();+     private:          /* Battlegrounds */         BattleGroundSet m_BattleGrounds;+        uint32 m_MaxRatingDifference;+        uint32 m_RatingDiscardTimer;+        uint32 m_NextRatingDiscardUpdate;+        bool   m_AutoDistributePoints;+        uint64 m_NextAutoDistributionTime;+        uint32 m_AutoDistributionTimeChecker; };  #define sBattleGroundMgr MaNGOS::Singleton<BattleGroundMgr>::Instance()Index: src/game/BattleGroundNA.cpp===================================================================--- src/game/BattleGroundNA.cpp	(revision 5306)+++ src/game/BattleGroundNA.cpp	(working copy)@@ -73,6 +73,9 @@             for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; i++)                 DoorOpen(i); +            for(uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; i++)+                SpawnBGObject(i, 60);+             SendMessageToAll(LANG_ARENA_BEGUN);             SetStatus(STATUS_IN_PROGRESS);             SetStartDelayTime(0);@@ -83,6 +86,11 @@                 if(plr)                     plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);             }++            if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+                EndBattleGround(HORDE);+            else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))+                EndBattleGround(ALLIANCE);         }     } @@ -92,9 +100,9 @@     }*/ } -void BattleGroundNA::AddPlayer(Player *plr)+void BattleGroundNA::AddPlayer(Player *plr, uint32 team) {-    BattleGround::AddPlayer(plr);+    BattleGround::AddPlayer(plr, team);     //create score and add it to map, default values are set in constructor     BattleGroundNAScore* sc = new BattleGroundNAScore; @@ -103,7 +111,13 @@  void BattleGroundNA::RemovePlayer(Player *plr, uint64 guid) {+    if(GetStatus() == STATUS_WAIT_LEAVE)+        return; +    if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+        EndBattleGround(HORDE);+    else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))+        EndBattleGround(ALLIANCE); }  void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer)@@ -117,15 +131,16 @@         return;     } -    uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());--    m_TeamKills[killer_team_index]++;                       // add kills to killer's team--    if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))+    if(!GetAlivePlayersCountByTeam(ALLIANCE))     {         // all opponents killed-        EndBattleGround(killer->GetTeam());+        EndBattleGround(HORDE);     }+    else if(!GetAlivePlayersCountByTeam(HORDE))+    {+        // all opponents killed+        EndBattleGround(ALLIANCE);+    } }  void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger)@@ -134,11 +149,14 @@         return;      uint32 SpellId = 0;-    uint64 buff_guid = 0;+    GameObject* obj = 0;     switch(Trigger)     {         case 4536:                                          // buff trigger?+            obj = m_BgObjects[BG_NA_OBJECT_BUFF_1];+            break;         case 4537:                                          // buff trigger?+            obj = m_BgObjects[BG_NA_OBJECT_BUFF_2];             break;         default:             sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);@@ -146,11 +164,8 @@             break;     } -    if(buff_guid)+    if(obj)     {-        GameObject *obj = HashMapHolder<GameObject>::Find(buff_guid);-        if(obj)-        {             if(!obj->isSpawned())                 return;                                     // buff not spawned yet             obj->SetRespawnTime(BUFF_RESPAWN_TIME);@@ -158,14 +173,12 @@             SpellId = obj->GetGOInfo()->data3;             if(SpellId)                 Source->CastSpell(Source, SpellId, true);-        }     } }  void BattleGroundNA::ResetBGSubclass() {-    m_TeamKills[BG_TEAM_ALLIANCE] = 0;-    m_TeamKills[BG_TEAM_HORDE]    = 0;+ }  bool BattleGroundNA::SetupBattleGround()@@ -174,7 +187,10 @@     if(    !AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854, 2966.833, 12.6462, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY)         || !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179, 2874.97, 12.39171, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY)         || !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709, 2981.777, 10.70117, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY)-        || !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064, 2858.438, 10.23631, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY))+        || !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064, 2858.438, 10.23631, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY)+    // buffs+        || !AddObject(BG_NA_OBJECT_BUFF_1, BG_NA_OBJECT_TYPE_BUFF_1, 4009.189941, 2895.250000, 13.052700, -1.448624, 0, 0, 0.6626201, -0.7489557, 120)+        || !AddObject(BG_NA_OBJECT_BUFF_2, BG_NA_OBJECT_TYPE_BUFF_2, 4103.330078, 2946.350098, 13.051300, -0.06981307, 0, 0, 0.03489945, -0.9993908, 120))     {         sLog.outErrorDb("BatteGroundNA: Failed to spawn some object!");         return false;Index: src/game/BattleGroundNA.h===================================================================--- src/game/BattleGroundNA.h	(revision 5306)+++ src/game/BattleGroundNA.h	(working copy)@@ -26,7 +26,9 @@     BG_NA_OBJECT_DOOR_2         = 1,     BG_NA_OBJECT_DOOR_3         = 2,     BG_NA_OBJECT_DOOR_4         = 3,-    BG_NA_OBJECT_MAX            = 4+    BG_NA_OBJECT_BUFF_1         = 4,+    BG_NA_OBJECT_BUFF_2         = 5,+    BG_NA_OBJECT_MAX            = 6 };  enum BattleGroundNAObjects@@ -34,7 +36,9 @@     BG_NA_OBJECT_TYPE_DOOR_1    = 183978,     BG_NA_OBJECT_TYPE_DOOR_2    = 183980,     BG_NA_OBJECT_TYPE_DOOR_3    = 183977,-    BG_NA_OBJECT_TYPE_DOOR_4    = 183979+    BG_NA_OBJECT_TYPE_DOOR_4    = 183979,+    BG_NA_OBJECT_TYPE_BUFF_1    = 184663,+    BG_NA_OBJECT_TYPE_BUFF_2    = 184664 };  class BattleGroundNAScore : public BattleGroundScore@@ -55,15 +59,12 @@         void Update(time_t diff);          /* inherited from BattlegroundClass */-        virtual void AddPlayer(Player *plr);+        virtual void AddPlayer(Player *plr, uint32 team = 0);          void RemovePlayer(Player *plr, uint64 guid);         void HandleAreaTrigger(Player *Source, uint32 Trigger);         bool SetupBattleGround();         virtual void ResetBGSubclass();         void HandleKillPlayer(Player* player, Player *killer);--    private:-        uint32 m_TeamKills[2];                              // count of kills for each team }; #endifIndex: src/game/BattleGroundRL.cpp===================================================================--- src/game/BattleGroundRL.cpp	(revision 5306)+++ src/game/BattleGroundRL.cpp	(working copy)@@ -74,6 +74,9 @@             for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++)                 DoorOpen(i); +            for(uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; i++)+                SpawnBGObject(i, 60);+             SendMessageToAll(LANG_ARENA_BEGUN);             SetStatus(STATUS_IN_PROGRESS);             SetStartDelayTime(0);@@ -84,6 +87,11 @@                 if(plr)                     plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);             }++            if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+                EndBattleGround(HORDE);+            else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))+                EndBattleGround(ALLIANCE);         }     } @@ -93,9 +101,9 @@     }*/ } -void BattleGroundRL::AddPlayer(Player *plr)+void BattleGroundRL::AddPlayer(Player *plr, uint32 team) {-    BattleGround::AddPlayer(plr);+    BattleGround::AddPlayer(plr, team);     //create score and add it to map, default values are set in constructor     BattleGroundRLScore* sc = new BattleGroundRLScore; @@ -104,7 +112,13 @@  void BattleGroundRL::RemovePlayer(Player *plr, uint64 guid) {+    if(GetStatus() == STATUS_WAIT_LEAVE)+        return; +    if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+        EndBattleGround(HORDE);+    else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))+        EndBattleGround(ALLIANCE); }  void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer)@@ -118,15 +132,16 @@         return;     } -    uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());--    m_TeamKills[killer_team_index]++;                       // add kills to killer's team--    if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))+    if(!GetAlivePlayersCountByTeam(ALLIANCE))     {         // all opponents killed-        EndBattleGround(killer->GetTeam());+        EndBattleGround(HORDE);     }+    else if(!GetAlivePlayersCountByTeam(HORDE))+    {+        // all opponents killed+        EndBattleGround(ALLIANCE);+    } }  void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger)@@ -136,11 +151,14 @@         return;      uint32 SpellId = 0;-    uint64 buff_guid = 0;+    GameObject* obj = 0;     switch(Trigger)     {         case 4696:                                          // buff trigger?+            obj = m_BgObjects[BG_RL_OBJECT_BUFF_1];+            break;         case 4697:                                          // buff trigger?+            obj = m_BgObjects[BG_RL_OBJECT_BUFF_2];             break;         default:             sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);@@ -148,11 +166,8 @@             break;     } -    if(buff_guid)+    if(obj)     {-        GameObject *obj = HashMapHolder<GameObject>::Find(buff_guid);-        if(obj)-        {             if(!obj->isSpawned())                 return;                                     // buff not spawned yet             obj->SetRespawnTime(BUFF_RESPAWN_TIME);@@ -160,21 +175,22 @@             SpellId = obj->GetGOInfo()->data3;             if(SpellId)                 Source->CastSpell(Source, SpellId, true);-        }     } }  void BattleGroundRL::ResetBGSubclass() {-    m_TeamKills[BG_TEAM_ALLIANCE] = 0;-    m_TeamKills[BG_TEAM_HORDE]    = 0;+ }  bool BattleGroundRL::SetupBattleGround() {     // gates     if(    !AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561, 1601.938, 31.60557, -1.457349, 0, 0, -0.6658813, 0.7460576, RESPAWN_IMMEDIATELY)-        || !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648, 1730.557, 31.60557, 1.684245, 0, 0, 0.7460582, 0.6658807, RESPAWN_IMMEDIATELY))+        || !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648, 1730.557, 31.60557, 1.684245, 0, 0, 0.7460582, 0.6658807, RESPAWN_IMMEDIATELY)+    // buffs+        || !AddObject(BG_RL_OBJECT_BUFF_1, BG_RL_OBJECT_TYPE_BUFF_1, 1328.719971, 1632.719971, 36.730400, -1.448624, 0, 0, 0.6626201, -0.7489557, 120)+        || !AddObject(BG_RL_OBJECT_BUFF_2, BG_RL_OBJECT_TYPE_BUFF_2, 1243.300049, 1699.170044, 34.872601, -0.06981307, 0, 0, 0.03489945, -0.9993908, 120))     {         sLog.outErrorDb("BatteGroundRL: Failed to spawn some object!");         return false;Index: src/game/BattleGroundRL.h===================================================================--- src/game/BattleGroundRL.h	(revision 5306)+++ src/game/BattleGroundRL.h	(working copy)@@ -24,13 +24,17 @@ {     BG_RL_OBJECT_DOOR_1         = 0,     BG_RL_OBJECT_DOOR_2         = 1,-    BG_RL_OBJECT_MAX            = 2+    BG_RL_OBJECT_BUFF_1         = 2,+    BG_RL_OBJECT_BUFF_2         = 3,+    BG_RL_OBJECT_MAX            = 4 };  enum BattleGroundRLObjects {     BG_RL_OBJECT_TYPE_DOOR_1    = 185918,-    BG_RL_OBJECT_TYPE_DOOR_2    = 185917+    BG_RL_OBJECT_TYPE_DOOR_2    = 185917,+    BG_RL_OBJECT_TYPE_BUFF_1    = 184663,+    BG_RL_OBJECT_TYPE_BUFF_2    = 184664 };  class BattleGroundRLScore : public BattleGroundScore@@ -51,15 +55,12 @@         void Update(time_t diff);          /* inherited from BattlegroundClass */-        virtual void AddPlayer(Player *plr);+        virtual void AddPlayer(Player *plr, uint32 team = 0);          void RemovePlayer(Player *plr, uint64 guid);         void HandleAreaTrigger(Player *Source, uint32 Trigger);         bool SetupBattleGround();         virtual void ResetBGSubclass();         void HandleKillPlayer(Player* player, Player *killer);--    private:-        uint32 m_TeamKills[2];                              // count of kills for each team }; #endifIndex: src/game/BattleGroundWS.cpp===================================================================--- src/game/BattleGroundWS.cpp	(revision 5306)+++ src/game/BattleGroundWS.cpp	(working copy)@@ -50,6 +50,9 @@         {             m_Events |= 0x01; +            for(uint32 i = WS_SPIRIT_MAIN_ALLIANCE; i <= WS_SPIRIT_MAIN_HORDE; i++)+                SpawnBGCreature(i, RESPAWN_IMMEDIATELY);+             for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++)                 SpawnBGObject(i, RESPAWN_IMMEDIATELY); @@ -111,9 +114,9 @@     } } -void BattleGroundWS::AddPlayer(Player *plr)+void BattleGroundWS::AddPlayer(Player *plr, uint32 team) {-    BattleGround::AddPlayer(plr);+    BattleGround::AddPlayer(plr, team);     //create score and add it to map, default values are set in constructor     BattleGroundWGScore* sc = new BattleGroundWGScore; @@ -388,7 +391,7 @@         return;      uint32 SpellId = 0;-    uint64 buff_guid = 0;+    GameObject* buff_guid = 0;     switch(Trigger)     {         case 3686:                                          // Alliance elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update().@@ -432,7 +435,7 @@      if(buff_guid)     {-        GameObject *obj = HashMapHolder<GameObject>::Find(buff_guid);+        GameObject *obj = buff_guid;         if(obj)         {             if(!obj->isSpawned())@@ -504,11 +507,13 @@     m_TeamScores[BG_TEAM_ALLIANCE]      = 0;     m_TeamScores[BG_TEAM_HORDE]         = 0; +/*  do not do this here, useless anyway     if(m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE])         DelCreature(WS_SPIRIT_MAIN_ALLIANCE);      if(m_BgCreatures[WS_SPIRIT_MAIN_HORDE])         DelCreature(WS_SPIRIT_MAIN_HORDE);+*/ }  void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer)Index: src/game/BattleGroundWS.h===================================================================--- src/game/BattleGroundWS.h	(revision 5306)+++ src/game/BattleGroundWS.h	(working copy)@@ -122,7 +122,7 @@         void Update(time_t diff);          /* inherited from BattlegroundClass */-        virtual void AddPlayer(Player *plr);+        virtual void AddPlayer(Player *plr, uint32 team = 0);          /* BG Flags */         uint64 GetAllianceFlagPickerGUID() const    { return m_FlagKeepers[BG_TEAM_ALLIANCE]; }Index: src/game/Chat.cpp===================================================================--- src/game/Chat.cpp	(revision 5306)+++ src/game/Chat.cpp	(working copy)@@ -387,6 +387,7 @@         { "cast",        SEC_ADMINISTRATOR, &ChatHandler::HandleCastCommand,             "",   NULL },         { "castback",    SEC_ADMINISTRATOR, &ChatHandler::HandleCastBackCommand,         "",   NULL },         { "casttarget",  SEC_ADMINISTRATOR, &ChatHandler::HandleCastTargetCommand,       "",   NULL },+        { "flusharenapoints",    SEC_ADMINISTRATOR, &ChatHandler::HandleFlushArenaPointsCommand,         "",   NULL },          //! Development Commands         { "setvalue",    SEC_ADMINISTRATOR, &ChatHandler::HandleSetValue,                "",   NULL },Index: src/game/Chat.h===================================================================--- src/game/Chat.h	(revision 5306)+++ src/game/Chat.h	(working copy)@@ -329,6 +329,7 @@         bool HandleCastCommand(const char *args);         bool HandleCastBackCommand(const char *args);         bool HandleCastTargetCommand(const char *args);+        bool HandleFlushArenaPointsCommand(const char *args);          //! Development Commands         bool HandleSetValue(const char* args);Index: src/game/ItemPrototype.h===================================================================--- src/game/ItemPrototype.h	(revision 5306)+++ src/game/ItemPrototype.h	(working copy)@@ -536,7 +536,7 @@     uint32 socketBonus;                                     // id from SpellItemEnchantment.dbc     uint32 GemProperties;                                   // id from GemProperties.dbc     uint32 ExtendedCost;                                    // id from ItemExtendedCost.dbc-    uint32 RequiredArenaRank;+    uint32 RequiredArenaRank;                               // id from ItemCondExtCosts.dbc     // note: this field should be renamed accordingly     uint32 RequiredDisenchantSkill;     float  ArmorDamageModifier;     char* ScriptName;Index: src/game/Language.h===================================================================--- src/game/Language.h	(revision 5306)+++ src/game/Language.h	(working copy)@@ -528,6 +528,13 @@     LANG_PLAYER_AFK                     = 708,     LANG_PLAYER_DND_DEFAULT             = 709,     LANG_PLAYER_AFK_DEFAULT             = 710,++    LANG_BG_GROUP_TOO_LARGE             = 7007, // "Your group is too large for this battleground. Please regroup to join."+    LANG_ARENA_GROUP_TOO_LARGE          = 7008, // "Your group is too large for this arena. Please regroup to join."+    LANG_ARENA_YOUR_TEAM_ONLY           = 7009, // "Your group has members not in your arena team. Please regroup to join."+    LANG_ARENA_NOT_ENOUGH_PLAYERS       = 7010, // "Your group does not have enough players to join this match."+    LANG_ARENA_GOLD_WINS                = 7011, // "The Gold Team wins!"+    LANG_ARENA_GREEN_WINS               = 7012 // "The Green Team wins!" };  /*  NOT USED VALUESIndex: src/game/Level3.cpp===================================================================--- src/game/Level3.cpp	(revision 5306)+++ src/game/Level3.cpp	(working copy)@@ -42,6 +42,7 @@ #include "SkillExtraItems.h" #include "SystemConfig.h" #include "Config/ConfigEnv.h"+#include "BattleGroundMgr.h"  //reload commands bool ChatHandler::HandleReloadCommand(const char* arg)@@ -4673,3 +4674,9 @@      return true; }++bool ChatHandler::HandleFlushArenaPointsCommand(const char * /*args*/)+{+    sBattleGroundMgr.DistributeArenaPoints();+    return true;+}Index: src/game/Map.cpp===================================================================--- src/game/Map.cpp	(revision 5306)+++ src/game/Map.cpp	(working copy)@@ -271,6 +271,10 @@     else         i_data = NULL; +    // flags if gridunloading is enabled / disabled on this map+    // needed, because bg objects aren't in the db, but added in runtime, and unloading the grids would destroy them+    i_unloadmap = sWorld.getConfig(CONFIG_GRID_UNLOAD);+     i_Players.clear(); } @@ -393,7 +397,7 @@         Guard guard(*this);         if(!getNGrid(p.x_coord, p.y_coord))         {-            setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_GRID_UNLOAD)),+            setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, i_unloadmap),                 p.x_coord, p.y_coord);              // build a linkage between this map and NGridType@@ -725,8 +729,9 @@ {     // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !     // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended-    if ((i_id == 489) || (i_id == 529))                     // WS, AB-        return;+    // no longer needed, the unloadmap flag will prevent unloading bg map grids+    // if ((i_id == 489) || (i_id == 529))                     // WS, AB+    //    return;      for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); )     {Index: src/game/Map.h===================================================================--- src/game/Map.h	(revision 5306)+++ src/game/Map.h	(working copy)@@ -149,6 +149,8 @@          bool GetUnloadFlag(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadFlag(); }         void SetUnloadFlag(const GridPair &p, bool unload) { getNGrid(p.x_coord, p.y_coord)->setUnloadFlag(unload); }+        void SetUnloadMap(bool unload){ i_unloadmap = unload; }+        bool GetUnloadMap() const { return i_unloadmap; }         void LoadGrid(const Cell& cell, bool no_unload = false);         bool UnloadGrid(const uint32 &x, const uint32 &y, bool pForce);         virtual void UnloadAll(bool pForce);@@ -207,7 +209,7 @@         bool CanEnter(Player* player) const;         const char* GetMapName() const; -        bool Instanceable() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID))); }+        bool Instanceable() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID) || (i_mapEntry->map_type == MAP_BATTLEGROUND) || (i_mapEntry->map_type == MAP_ARENA))); }         // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable         bool IsDungeon() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID))); }         bool IsRaid() const { return(i_mapEntry && (i_mapEntry->map_type == MAP_RAID)); }@@ -295,6 +297,7 @@         uint32 i_resetDelayTime;         uint32 i_InstanceId;         uint32 i_maxPlayers;+        bool i_unloadmap;         InstanceData* i_data;         std::string i_script; Index: src/game/MapInstanced.cpp===================================================================--- src/game/MapInstanced.cpp	(revision 5306)+++ src/game/MapInstanced.cpp	(working copy)@@ -44,6 +44,7 @@         {             if (i->second->GetPlayersCount() == 0)             {+                DEBUG_LOG("reseting instance in update for instance id = %u and map id = %u named %s",this->GetInstanceId(),this->GetId(),this->GetMapName());                 i->second->Reset();                 // avoid doing ++ on invalid data                 InstancedMaps::iterator i_old = i;@@ -187,7 +188,7 @@          if (!instantiator && instantiator_online)         {-            sLog.outDebug("MAPINSTANCED: Player '%s' is not in group, instantiating map for player", player->GetName());+            sLog.outDebug("MAPINSTANCED: Player '%s' is not in group, instantiating map %u for player", player->GetName(), GetId());             instantiator = player;         } @@ -230,11 +231,13 @@         // check, if we have to generate new instance         if (!instantiator_bound || (InstanceId == 0))         {+            sLog.outDebug("MAPINSTANCED: Generating new instance id");             // yes, new instance id has to be generated             InstanceId = MapManager::Instance().GenerateInstanceId();         }         else         {+            sLog.outDebug("MAPINSTANCED: Instantiator bound, finding map...");             // find map of the designated instance and verify it             map = _FindMap(InstanceId);         }@@ -242,7 +245,7 @@      // now create the instance     CreateInstance(InstanceId, map);-+    sLog.outDebug("MAPINSTANCED::GetInstance() Instance Created");     // we do need to bind instance, if the instance we use is valid, not temporary     if (player->m_InstanceValid)     {@@ -304,6 +307,7 @@             // map for the instance is present, but the instance itself is no more valid, destroy map             Guard guard(*this); +            DEBUG_LOG("reseting instance in createinstance for instance id = %u and map id = %u named %s",this->GetInstanceId(),this->GetId(),this->GetMapName());             map->Reset();             m_InstancedMaps.erase(InstanceId);             delete map;@@ -314,10 +318,13 @@     // verify, if we have the map created, and create it if needed     if (!map)     {+        sLog.outDebug("MAPINSTANCED: CreateInstance, map not found, creating it");         // map does not exist, create it         Guard guard(*this);          map = new Map(GetId(), GetGridExpiry(), InstanceId);+        // set the unload map flag according to the base map's flag+        map->SetUnloadMap(GetUnloadMap());         m_InstancedMaps[InstanceId] = map;     } }Index: src/game/MapManager.cpp===================================================================--- src/game/MapManager.cpp	(revision 5306)+++ src/game/MapManager.cpp	(working copy)@@ -104,7 +104,7 @@         Guard guard(*this);          const MapEntry* entry = sMapStore.LookupEntry(id);-        if (entry && ((entry->map_type == MAP_INSTANCE) || (entry->map_type == MAP_RAID)))+        if (entry && ((entry->map_type == MAP_INSTANCE) || (entry->map_type == MAP_RAID) || (entry->map_type == MAP_BATTLEGROUND) || (entry->map_type == MAP_ARENA)))         {             m = new MapInstanced(id, i_gridCleanUpDelay, 0);         }Index: src/game/MovementHandler.cpp===================================================================--- src/game/MovementHandler.cpp	(revision 5306)+++ src/game/MovementHandler.cpp	(working copy)@@ -93,17 +93,21 @@         {             if(bg->GetMapId() == _player->GetMapId())       // we teleported to bg             {-                if(!bg->GetBgRaid(_player->GetTeam()))      // first player joined+                // get the team this way, because arenas might 'override' the teams.+                uint32 team = bg->GetPlayerTeam(_player->GetGUID());+                if(!team)+                    team = _player->GetTeam();+                if(!bg->GetBgRaid(team))      // first player joined                 {                     Group *group = new Group;-                    bg->SetBgRaid(_player->GetTeam(), group);+                    bg->SetBgRaid(team, group);                     group->ConvertToRaid();                     group->AddMember(_player->GetGUID(), _player->GetName());                     group->ChangeLeader(_player->GetGUID());                 }                 else                                        // raid already exist                 {-                    bg->GetBgRaid(_player->GetTeam())->AddMember(_player->GetGUID(), _player->GetName());+                    bg->GetBgRaid(team)->AddMember(_player->GetGUID(), _player->GetName());                 }             }         }@@ -504,3 +508,11 @@     _player->SummonIfPossible(); } ++++++++Index: src/game/ObjectMgr.cpp===================================================================--- src/game/ObjectMgr.cpp	(revision 5306)+++ src/game/ObjectMgr.cpp	(working copy)@@ -1340,6 +1340,10 @@         if(proto->ExtendedCost && !sItemExtendedCostStore.LookupEntry(proto->ExtendedCost))             sLog.outErrorDb("Item (Entry: %u) has wrong ExtendedCost (%u)",i,proto->ExtendedCost); +        // check if the extended cost and the required arena rank pair is valid (does it have entry in ItemCondExtCosts.dbc?)+        if(proto->ExtendedCost && proto->RequiredArenaRank && !GetItemCondExtCostsMask(proto->RequiredArenaRank, proto->ExtendedCost))+            sLog.outErrorDb("Item (Entry: %u) has wrong ExtendedCost - RequiredArenaRank pair (%u, %u)",i,proto->ExtendedCost,proto->RequiredArenaRank);+         if(proto->FoodType >= MAX_PET_DIET)         {             sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType);Index: src/game/PetitionsHandler.cpp===================================================================--- src/game/PetitionsHandler.cpp	(revision 5306)+++ src/game/PetitionsHandler.cpp	(working copy)@@ -49,9 +49,6 @@ {     CHECK_PACKET_SIZE(recv_data, 8+8+4+1+5*8+2+1+4+4); -    if(_player->GetGuildId())-        return;-     sLog.outDebug("Received opcode CMSG_PETITION_BUY");     //recv_data.hexlike(); @@ -95,6 +92,11 @@     uint32 type = 0;     if(pCreature->isTabardDesigner())     {+        // if tabard designer, then trying to buy a guild charter.+        // do not let if already in guild.+        if(_player->GetGuildId())+            return;+         charterid = GUILD_CHARTER;         cost = GUILD_CHARTER_COST;         type = 9;@@ -102,7 +104,7 @@     else     {         // TODO: find correct opcode-        if(_player->getLevel() != 70)+        if(_player->getLevel() < 70)         {             SendNotification(objmgr.GetMangosString(LANG_ARENA_ONE_TOOLOW, GetSessionLocaleIndex()), 70);             return;@@ -188,10 +190,31 @@     charter->SetState(ITEM_CHANGED, _player);     _player->SendNewItem(charter, 1, true, false); +    // a petition is invalid, if both the owner and the type matches+    QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u'  AND type = '%u'", _player->GetGUIDLow(), type);++    std::ostringstream ssInvalidPetitionGUIDs;++    if (result)+    {++        do+        {+            Field *fields = result->Fetch();+            ssInvalidPetitionGUIDs << "'" << fields[0].GetUInt32() << "' , ";+        } while (result->NextRow());++        delete result;+    }++    // delete petitions with the same guid as this one+    ssInvalidPetitionGUIDs << "'" << charter->GetGUIDLow() << "'";++    sLog.outDebug("Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str());     CharacterDatabase.escape_string(name);     CharacterDatabase.BeginTransaction();-    CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u' OR petitionguid = '%u' and type = '%u'", _player->GetGUIDLow(), charter->GetGUIDLow(),type);-    CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u' or petitionguid = '%u'", _player->GetGUIDLow(), charter->GetGUIDLow());+    CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid IN ( %s )",  ssInvalidPetitionGUIDs.str().c_str());+    CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid IN ( %s )", ssInvalidPetitionGUIDs.str().c_str());     CharacterDatabase.PExecute("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')",         _player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type);     CharacterDatabase.CommitTransaction();@@ -205,9 +228,6 @@     sLog.outDebug("Received opcode CMSG_PETITION_SHOW_SIGNATURES");     //recv_data.hexlike(); -    if(_player->GetGuildId())-        return;-     uint8 signs = 0;     uint64 petitionguid;     recv_data >> petitionguid;                              // petition guid@@ -215,14 +235,18 @@     // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?)     uint32 petitionguid_low = GUID_LOPART(petitionguid); -    QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE petitionguid = '%u'", petitionguid_low);+    QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid, type FROM petition WHERE petitionguid = '%u'", petitionguid_low);     if(!result)     {         sLog.outError("any petition on server...");         return;     }-+    Field *fields = result->Fetch();+    uint32 type = fields[1].GetUInt32();     delete result;+    // if guild petition and has guild => error, return;+    if(type==9 && _player->GetGuildId())+        return;      result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low); @@ -317,13 +341,14 @@     {         data << uint32(9);         data << uint32(9);+        data << uint32(0);                                  // bypass client - side limitation, a different value is needed here for each petition     }     else     {         data << type-1;         data << type-1;+        data << type;                                       // bypass client - side limitation, a different value is needed here for each petition     }-    data << uint32(0);                                      // 4     data << uint32(0);                                      // 5     data << uint32(0);                                      // 6     data << uint32(0);                                      // 7@@ -457,13 +482,20 @@         return;     } +    if(type != 9 && _player->getLevel() < 70)+    {+        // player is too low level to join an arena team+        SendNotification("You must be level 70 to join an arena team!");+        return;+    }+     signs += 1;     if(signs > type)                                        // client signs maximum         return;      //client doesn't allow to sign petition two times by one character, but not check sign by another character from same account     //not allow sign another player from already sign player account-    result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u'", GetAccountId());+    result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid));      if(result)     {@@ -638,16 +670,29 @@     }     else     {-        for(uint8 i = 0; i < 3; i++)+        uint32 type_slot;+        switch(type)         {-            if(_player->GetArenaTeamId(i))-            {+        case ARENA_TEAM_2v2:+            type_slot = 0;+            break;+        case ARENA_TEAM_3v3:+            type_slot = 1;+            break;+        case ARENA_TEAM_5v5:+            type_slot = 2;+            break;+        default:+            type_slot = 0;+            break;+        }+        if(_player->GetArenaTeamId(type_slot))+        {                 //data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);                 //data << (uint32)PETITION_TURN_ALREADY_IN_GUILD;                          // already in guild                 //_player->GetSession()->SendPacket(&data);                 SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);                 return;-            }         }     } @@ -735,6 +780,7 @@         ArenaTeam* at = new ArenaTeam;         if(!at->create(_player->GetGUID(), type, name))         {+            sLog.outError("PetitionsHandler: arena team create failed.");             delete at;             delete result;             return;@@ -748,11 +794,13 @@          // register team and add captain         objmgr.AddArenaTeam(at);+        sLog.outDebug("PetitonsHandler: arena team added to objmrg");          // add members         for(uint8 i = 0; i < signs; ++i)         {             Field* fields = result->Fetch();+            sLog.outDebug("PetitionsHandler: adding arena member %u", fields[0].GetUInt64());             at->AddMember(fields[0].GetUInt64());             result->NextRow();         }@@ -820,21 +868,21 @@         data << uint32(ARENA_TEAM_CHARTER_2v2);             // charter entry         data << uint32(16161);                              // charter display id         data << uint32(ARENA_TEAM_CHARTER_2v2_COST);        // charter cost-        data << uint32(0);                                  // unknown+        data << uint32(2);                                  // unknown         data << uint32(2);                                  // required signs?         // 3v3         data << uint32(2);                                  // index         data << uint32(ARENA_TEAM_CHARTER_3v3);             // charter entry         data << uint32(16161);                              // charter display id         data << uint32(ARENA_TEAM_CHARTER_3v3_COST);        // charter cost-        data << uint32(0);                                  // unknown+        data << uint32(3);                                  // unknown         data << uint32(3);                                  // required signs?         // 5v5         data << uint32(3);                                  // index         data << uint32(ARENA_TEAM_CHARTER_5v5);             // charter entry         data << uint32(16161);                              // charter display id         data << uint32(ARENA_TEAM_CHARTER_5v5_COST);        // charter cost-        data << uint32(0);                                  // unknown+        data << uint32(5);                                  // unknown         data << uint32(5);                                  // required signs?     }     //for(uint8 i = 0; i < count; i++)Index: src/game/Player.cpp===================================================================--- src/game/Player.cpp	(revision 5306)+++ src/game/Player.cpp	(working copy)@@ -1252,8 +1252,8 @@      bool state = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); -    // afk player not allowed in battleground-    if(state && InBattleGround())+    // afk player not allowed in battleground ( do net check this in arena )+    if(state && InBattleGround() && GetBattleGround() && GetBattleGround()->isBattleGround())         LeaveBattleground();      return state;@@ -1436,7 +1436,7 @@     sLog.outDebug( "WORLD: Sent (SMSG_IGNORE_LIST)" ); } -void Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange, bool ignore_transport, bool is_gm_command)+void Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange, bool ignore_transport, bool is_gm_command, bool battleground_port) {     // preparing unsummon pet if lost (we must get pet before teleportation or will not find it later)     Pet* pet = GetPet();@@ -1596,7 +1596,8 @@         Map* map = MapManager::Instance().GetMap(mapid, this);         // verify, if it does want to homebind us (but only if we are not in GM state,         // GMs are allowed to teleport everywhere they want to be)-        if (!m_InstanceValid && (!isGameMaster() || !is_gm_command))+        // battlegrounds do NOT homebind+        if (!m_InstanceValid && (!isGameMaster() || !is_gm_command) && !battleground_port)         {             // yes, we are going to be homebind, avoid this action :)             SetInstanceId(0);                               // reset instance id@@ -2727,6 +2728,32 @@         removeSpell(itr->second.spell); } +void Player::RemoveArenaSpellCooldowns()+{+    // remove cooldowns on spells that has < 15 min CD+    SpellCooldowns::iterator itr, next;+    // iterate spell cooldowns+    for(itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); itr = next)+    {+        next = itr;+        ++next;+        SpellEntry const * entry = sSpellStore.LookupEntry(itr->first);+        // check if spellentry is present and if the cooldown is less than 15 mins+        if( entry && +            (entry->RecoveryTime <= 15 * 60000) &&+            (entry->CategoryRecoveryTime <= 15 * 60000))+        {+            // notify player+            WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8+4));+            data << uint32(itr->first);+            data << GetGUID();+            GetSession()->SendPacket(&data);+            // remove cooldown+            m_spellCooldowns.erase(itr);+        }+    }+}+ void Player::RemoveAllSpellCooldown() {     if(!m_spellCooldowns.empty())@@ -5538,6 +5565,10 @@     uint32 now = time(NULL);     UpdateHonorFields(); +    // do not reward honor in arenas+    if(InBattleGround() && GetBattleGround() && GetBattleGround()->isArena())+        return false;+     if(honor <= 0)     {         if(!uVictim || uVictim == this || uVictim->GetAura(2479, 0))@@ -5659,27 +5690,33 @@         return 0; } -uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 slot)+uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type) {     // need fix it!     QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid FROM arena_team_member WHERE guid='%u'", GUID_LOPART(guid));     if(result)     {-        uint32 id = (*result)[0].GetUInt32();+        // init id to 0, check the arena type before assigning a value to id+        uint32 id = 0;         do         {             QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM arena_team WHERE arenateamid='%u'", id);             if(result2)             {-                uint8 dbslot = (*result2)[0].GetUInt32();+                uint8 dbtype = (*result2)[0].GetUInt32();                 delete result2;-                if(dbslot == slot)+                if(dbtype == type)+                {+                    // if the type matches, we've found the id+                    id = (*result)[0].GetUInt32();                     break;+                }             }         } while(result->NextRow());         delete result;         return id;     }+    // no arenateam for the specified guid, return 0     return 0; } @@ -8725,6 +8762,13 @@                 pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD && pProto->InventoryType != INVTYPE_RELIC)                 return EQUIP_ERR_NOT_IN_COMBAT; +            // do not allow gear change during in-progress arena matches, only weapons / offhands / relics / ammo+            if( InBattleGround() && GetBattleGround() && GetBattleGround()->isArena() && +                (GetBattleGround()->GetStatus() == STATUS_IN_PROGRESS) &&+                (pProto->Class != ITEM_CLASS_WEAPON) && (pProto->Class != ITEM_CLASS_PROJECTILE) &&+                (pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD) && (pProto->InventoryType != INVTYPE_RELIC))+                return EQUIP_ERR_NOT_DURING_ARENA_MATCH;+             if(isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer != 0)                 return EQUIP_ERR_CANT_DO_RIGHT_NOW;         // maybe exist better err @@ -8853,6 +8897,13 @@         pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD && pProto->InventoryType != INVTYPE_RELIC )         return EQUIP_ERR_NOT_IN_COMBAT; +    // do not allow unequipping gear in in-progress arenas, except weapons, offhands, projectiles, relics+    if( InBattleGround() && GetBattleGround() && GetBattleGround()->isArena() && +        (GetBattleGround()->GetStatus() == STATUS_IN_PROGRESS) &&+        (pProto->Class != ITEM_CLASS_WEAPON) && (pProto->Class != ITEM_CLASS_PROJECTILE) &&+        (pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD) && (pProto->InventoryType != INVTYPE_RELIC))+        return EQUIP_ERR_NOT_DURING_ARENA_MATCH;+     if(!swap && pItem->IsBag() && !((Bag*)pItem)->IsEmpty())         return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS; @@ -9887,6 +9938,54 @@     } } +void Player::DestroyConjuredItems( bool update )+{+    // used when entering arena+    // distroys all conjured items+    sLog.outDebug( "STORAGE: DestroyConjuredItems" );++    // in inventory+    for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)+    {+        Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );+        if( pItem && pItem->GetProto() &&+            (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && +            (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )+            DestroyItem( INVENTORY_SLOT_BAG_0, i, update);+    }++    // in inventory bags+    for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)+    {+        Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );+        if( pBag )+        {+            ItemPrototype const *pBagProto = pBag->GetProto();+            if( pBagProto )+            {+                for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)+                {+                    Item* pItem = pBag->GetItemByPos(j);+                    if( pItem && pItem->GetProto() &&+                        (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && +                        (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )+                        DestroyItem( i, j, update);+                }+            }+        }+    }++    // in equipment and bag list+    for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)+    {+        Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );+        if( pItem && pItem->GetProto() &&+            (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && +            (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )+            DestroyItem( INVENTORY_SLOT_BAG_0, i, update);+    }+}+ void Player::DestroyItemCount( Item* pItem, uint32 &count, bool update ) {     if(!pItem)@@ -14894,11 +14993,15 @@  void Player::RemovePetitionsAndSigns(uint64 guid, uint32 type) {-    QueryResult *result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid));+    QueryResult *result = NULL;+    if(type==10)+        result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid));+    else+        result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type);     if(result)     {-        do-        {+        do    // this part effectively does nothing, since the deletion / modification only takes place _after_ the PetitionQuery. Though I don't know if the result remains intact if I execute the delete query beforehand.+        {     // and SendPetitionQueryOpcode reads data from the DB             Field *fields = result->Fetch();             uint64 ownerguid   = MAKE_GUID(fields[0].GetUInt32(), HIGHGUID_PLAYER);             uint64 petitionguid = MAKE_GUID(fields[1].GetUInt32(), HIGHGUID_ITEM);@@ -14912,15 +15015,23 @@          delete result; -        CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid));+        if(type==10)+            CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid));+        else+            CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type);     }      CharacterDatabase.BeginTransaction();     if(type == 10)+    {         CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u'", GUID_LOPART(guid));+        CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u'", GUID_LOPART(guid));+    }     else+    {         CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type);-    CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u'", GUID_LOPART(guid));+        CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type);+    }     CharacterDatabase.CommitTransaction(); } @@ -15280,6 +15391,9 @@         if(pProto->ExtendedCost)         {             ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(pProto->ExtendedCost);+            uint32 mask = 0;+            if(pProto->RequiredArenaRank)+                mask = GetItemCondExtCostsMask(pProto->RequiredArenaRank, pProto->ExtendedCost);             if(iece)             {                 if(GetHonorPoints() < (iece->reqhonorpoints * count))@@ -15299,6 +15413,13 @@                     SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL);                     return false;                 }+                // check for personal arena rating requirement+                if( (mask & (1<<3)) && (GetMaxPersonalArenaRatingRequirement() < iece->reqpersonalarenarating) )+                {+                    // probably not the proper equip err+                    SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK,NULL,NULL);+                    return false;+                }             }             else             {@@ -15434,6 +15555,26 @@     return false; } +uint32 Player::GetMaxPersonalArenaRatingRequirement()+{+    // returns the maximal personal arena rating that can be used to purchase items requiring this condition+    // the personal rating of the arena team must match the required limit as well+    // so return max[in arenateams](min(personalrating[teamtype], teamrating[teamtype]))+    uint32 max_personal_rating = 0;+    for(int i = 0; i < 3; ++i)+    {+        if(ArenaTeam * at = objmgr.GetArenaTeamById(GetArenaTeamId(i)))+        {+            uint32 p_rating = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (i * 6) + 5);+            uint32 t_rating = at->GetRating();+            p_rating = p_rating<t_rating? p_rating : t_rating;+            if(max_personal_rating < p_rating)+                max_personal_rating = p_rating;+        }+    }+    return max_personal_rating;+}+ void Player::_SaveBoundInstances() {     CharacterDatabase.PExecute("DELETE FROM character_instance WHERE (guid = '%u')", GetGUIDLow());@@ -16163,7 +16304,8 @@  bool Player::GetBGAccessByLevel(uint32 bgTypeId) const {-    BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);+    // get a template bg instead of running one+    BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);     if(!bg)         return false; Index: src/game/Player.h===================================================================--- src/game/Player.h	(revision 5306)+++ src/game/Player.h	(working copy)@@ -860,7 +860,7 @@         void AddToWorld();         void RemoveFromWorld(); -        void TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange = true, bool ignore_transport = true, bool is_gm_command = false);+        void TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange = true, bool ignore_transport = true, bool is_gm_command = false, bool battleground_port = false);          void SetSummonPoint(uint32 mapid, float x, float y, float z)         {@@ -1039,6 +1039,7 @@         void DestroyItem( uint8 bag, uint8 slot, bool update );         void DestroyItemCount( uint32 item, uint32 count, bool update, bool unequip_check = false);         void DestroyItemCount( Item* item, uint32& count, bool update );+        void DestroyConjuredItems( bool update );         void DestroyZoneLimitedItem( bool update, uint32 new_zone );         void SplitItem( uint16 src, uint16 dst, uint32 count );         void SwapItem( uint16 src, uint16 dst );@@ -1350,6 +1351,7 @@         void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time);         void ProhibitSpellScholl(SpellSchools idSchool, uint32 unTimeMs );         void RemoveSpellCooldown(uint32 spell_id) { m_spellCooldowns.erase(spell_id); }+        void RemoveArenaSpellCooldowns();         void RemoveAllSpellCooldown();         void _LoadSpellCooldowns(QueryResult *result);         void _SaveSpellCooldowns();@@ -1598,6 +1600,7 @@         bool RewardHonor(Unit *pVictim, uint32 groupsize, float honor = -1);         uint32 GetHonorPoints() { return GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY); }         uint32 GetArenaPoints() { return GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY); }+        uint32 GetMaxPersonalArenaRatingRequirement();         void SetHonorPoints(uint32 val) { SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, val); }         void SetArenaPoints(uint32 val) { SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, val); }         void SetFlushKills(bool value) { m_flushKills = value; }@@ -1715,9 +1718,11 @@         float GetBattleGroundEntryPointY() const { return m_bgEntryPointY; }         float GetBattleGroundEntryPointZ() const { return m_bgEntryPointZ; }         float GetBattleGroundEntryPointO() const { return m_bgEntryPointO; }-        void SetBattleGroundEntryPoint(uint32 Map, float PosX, float PosY, float PosZ, float PosO )+        uint32 GetBattleGroundEntryPointInstanceId() const { return m_bgEntryPointInstanceId; }+        void SetBattleGroundEntryPoint(uint32 Map, uint32 InstanceId, float PosX, float PosY, float PosZ, float PosO )         {             m_bgEntryPointMap = Map;+            m_bgEntryPointInstanceId = InstanceId;             m_bgEntryPointX = PosX;             m_bgEntryPointY = PosY;             m_bgEntryPointZ = PosZ;@@ -1864,6 +1869,7 @@         */         uint32 m_bgBattleGroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES];         uint32 m_bgEntryPointMap;+        uint32 m_bgEntryPointInstanceId;         float m_bgEntryPointX;         float m_bgEntryPointY;         float m_bgEntryPointZ;Index: src/game/Spell.cpp===================================================================--- src/game/Spell.cpp	(revision 5306)+++ src/game/Spell.cpp	(working copy)@@ -2454,12 +2454,20 @@      Player* p_caster = (Player*)m_caster; +    // if arena preparation is on, don't take soul shards+    bool bArenaPrep = p_caster->HasAura(SPELL_ARENA_PREPARATION, 0);+     for(uint32 x=0;x<8;x++)     {         if(m_spellInfo->Reagent[x] <= 0)             continue;          uint32 itemid = m_spellInfo->Reagent[x];++        // don't take soul shards if arena prep is on+        if(bArenaPrep && (itemid == 6265))+            continue;+         uint32 itemcount = m_spellInfo->ReagentCount[x];          // if CastItem is also spell reagent@@ -2675,6 +2683,15 @@     if((m_spellInfo->AttributesEx3 & 0x800) != 0)         return SPELL_FAILED_ONLY_BATTLEGROUNDS; +    // do not allow spells with greater than 15 min CD to be cast in arenas+    if( m_caster->GetTypeId() == TYPEID_PLAYER && +        ((Player*)m_caster)->InBattleGround() && +        ((Player*)m_caster)->GetBattleGround() && +        ((Player*)m_caster)->GetBattleGround()->isArena() &&+        (m_spellInfo->RecoveryTime > 15 * 60000 ||+        m_spellInfo->CategoryRecoveryTime > 15 * 60000) )+        return SPELL_FAILED_NOT_IN_ARENA;+     // zone check     uint32 zone_id = m_caster->GetZoneId(); @@ -3626,6 +3643,9 @@         focusObject = ok;                                   // game object found in range     } +    // check if arena prep is up+    bool bArenaPrep = p_caster->HasAura(SPELL_ARENA_PREPARATION, 0);+     for(uint32 i=0;i<8;i++)     {         if(m_spellInfo->Reagent[i] <= 0)@@ -3633,26 +3653,36 @@          itemid    = m_spellInfo->Reagent[i];         itemcount = m_spellInfo->ReagentCount[i];-        -        // if CastItem is also spell reagent-        if( m_CastItem && m_CastItem->GetEntry() == itemid )++        if( m_CastItem )         {-            ItemPrototype const *proto = m_CastItem->GetProto();-            if(!proto)-                return SPELL_FAILED_ITEM_NOT_READY;-            for(int s=0;s<5;s++)+            // if CastItem is also spell reagent+            if( m_CastItem->GetEntry() == itemid )             {-                // CastItem will be used up and does not count as reagent-                int32 charges = m_CastItem->GetSpellCharges(s);-                if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)+                ItemPrototype const *proto = m_CastItem->GetProto();+                if(!proto)+                    return SPELL_FAILED_ITEM_NOT_READY;+                for(int s=0;s<5;s++)                 {-                    itemcount++;-                    break;+                    // CastItem will be used up and does not count as reagent+                    int32 charges = m_CastItem->GetSpellCharges(s);+                    if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)+                    {+                        itemcount++;+                        break;+                    }                 }             }+            if( !p_caster->HasItemCount(itemid,itemcount) )+                return (uint8)SPELL_FAILED_ITEM_NOT_READY;      //0x54         }-        if( !p_caster->HasItemCount(itemid,itemcount) )-            return (uint8)SPELL_FAILED_ITEM_NOT_READY;      //0x54+        // if arena preparation is up, don't take soul shards, but take other reagents+        // this cannot happen in case of a m_CastItem, so it's enough to check here+        else if (!bArenaPrep || itemid != 6265)+        {+            if( !p_caster->HasItemCount(itemid,itemcount) )+                return (uint8)SPELL_FAILED_ITEM_NOT_READY;      //0x54+        }     }      uint32 totems = 2;Index: src/game/SpellHandler.cpp===================================================================--- src/game/SpellHandler.cpp	(revision 5306)+++ src/game/SpellHandler.cpp	(working copy)@@ -66,6 +66,15 @@         return;     } +    // only allow conjured consumable, bandage+    if ( pUser->InBattleGround() && pUser->GetBattleGround() && pUser->GetBattleGround()->isArena()+         && (proto->Class == ITEM_CLASS_CONSUMABLE) && !(proto->Flags & ITEM_FLAGS_CONJURED) && !(proto->SubClass == ITEM_SUBCLASS_BANDAGE))+    {+        //send use error: not in arena+        pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL);+        return;+    }+     if (pUser->isInCombat())     {         for(int i = 0; i < 5; ++i)@@ -468,7 +477,8 @@                             if(((BattleGroundWS*)bg)->GetFlagState(ALLIANCE) != BG_WS_FLAG_STATE_ON_BASE)                                 return;                             // check if it's correct flag-                            if(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_A_FLAG] != obj->GetGUID())+                            if(!(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_A_FLAG]) ||+                                (((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_A_FLAG]->GetGUID() != obj->GetGUID()))                                 return;                             // check player team                             if(_player->GetTeam() == ALLIANCE)@@ -483,7 +493,8 @@                             if(((BattleGroundWS*)bg)->GetFlagState(HORDE) != BG_WS_FLAG_STATE_ON_BASE)                                 return;                             // check if it's correct flag-                            if(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_H_FLAG] != obj->GetGUID())+                            if(!(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_H_FLAG]) ||+                                (((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_H_FLAG]->GetGUID() != obj->GetGUID()))                                 return;                             // check player team                             if(_player->GetTeam() == HORDE)Index: src/game/Unit.cpp===================================================================--- src/game/Unit.cpp	(revision 5306)+++ src/game/Unit.cpp	(working copy)@@ -566,36 +566,6 @@      if (health <= damage)     {-        // battleground things-        if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))-        {-            Player *killed = ((Player*)pVictim);-            Player *killer = NULL;-            if(GetTypeId() == TYPEID_PLAYER)-                killer = ((Player*)this);-            else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())-            {-                Unit *owner = GetOwner();-                if(owner && owner->GetTypeId() == TYPEID_PLAYER)-                    killer = ((Player*)owner);-            }--            if(killer)-            {-                if(BattleGround *bg = killed->GetBattleGround())-                {-                    bg->HandleKillPlayer(killed, killer);   // drop flags and etc-                    // add +1 deaths-                    bg->UpdatePlayerScore(killed, SCORE_DEATHS, 1);-                    if(killer)-                        // add +1 kills-                        bg->UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);-                    // to be able to remove insignia-                    killed->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );-                }-            }-        }-         DEBUG_LOG("DealDamage: victim just died");          DEBUG_LOG("DealDamageAttackStop");@@ -839,6 +809,39 @@              he->DuelComplete(DUEL_INTERUPTED);         }++        // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)+        if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))+        {+            Player *killed = ((Player*)pVictim);+            Player *killer = NULL;+            if(GetTypeId() == TYPEID_PLAYER)+                killer = ((Player*)this);+            else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())+            {+                Unit *owner = GetOwner();+                if(owner && owner->GetTypeId() == TYPEID_PLAYER)+                    killer = ((Player*)owner);+            }++            if(killer)+            {+                if(BattleGround *bg = killed->GetBattleGround())+                {+                    bg->HandleKillPlayer(killed, killer);   // drop flags and etc+                    // add +1 deaths+                    bg->UpdatePlayerScore(killed, SCORE_DEATHS, 1);+                    if(killer)+                    {+                        // add +1 kills+                        bg->UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);+                        bg->UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);+                    }+                    // to be able to remove insignia+                    killed->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );+                }+            }+        }     }     else                                                    // if (health <= damage)     {@@ -3900,6 +3903,19 @@     } } +void Unit::RemoveArenaAuras(bool onleave)+{+    // in join, remove positive buffs, on end, remove negative+    // used to remove positive visible auras in arenas+    for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)+    {+        if (!iter->second->IsPassive() && (iter->second->IsPositive() ^ onleave))+            RemoveAura(iter, true);+        else+            ++iter;+    }+}+ void Unit::RemoveAllAurasOnDeath() {     // used just after dieing to remove all visible aurasIndex: src/game/Unit.h===================================================================--- src/game/Unit.h	(revision 5306)+++ src/game/Unit.h	(working copy)@@ -819,6 +819,7 @@         void RemoveAreaAurasByOthers(uint64 guid = 0);          void RemoveAllAuras();+        void RemoveArenaAuras(bool onleave = false);         void RemoveAllAurasOnDeath();         void DelayAura(uint32 spellId, uint32 effindex, int32 delaytime);         bool SetAurDuration(uint32 spellId, uint32 effindex, uint32 duration);Index: src/game/World.cpp===================================================================--- src/game/World.cpp	(revision 5306)+++ src/game/World.cpp	(working copy)@@ -491,6 +491,10 @@     m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true);     m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false); +    m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault("Arena.MaxRatingDifference", 0);+    m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault("Arena.RatingDiscardTimer",300000);+    m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false);+     m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);     if(m_VisibleUnitGreyDistance >  MAX_VISIBILITY_DISTANCE)     {@@ -827,6 +831,7 @@     ///- Initialize Battlegrounds     sLog.outString( "Starting BattleGround System" );     sBattleGroundMgr.CreateInitialBattleGrounds();+    sBattleGroundMgr.InitAutomaticArenaPointDistribution();      //Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager     sLog.outString( "Loading Transports..." );Index: src/game/World.h===================================================================--- src/game/World.h	(revision 5306)+++ src/game/World.h	(working copy)@@ -118,6 +118,9 @@     CONFIG_TALENTS_INSPECTING,     CONFIG_CHAT_FAKE_MESSAGE_PREVENTING,     CONFIG_TCP_NO_DELAY,+    CONFIG_ARENA_MAX_RATING_DIFFERENCE,+    CONFIG_ARENA_RATING_DISCARD_TIMER,+    CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS,     CONFIG_VALUE_COUNT }; Index: src/mangosd/mangosd.conf.in===================================================================--- src/mangosd/mangosd.conf.in	(revision 5306)+++ src/mangosd/mangosd.conf.in	(working copy)@@ -538,3 +538,16 @@ # Default: 0 (false) #          1 (true) Event.Announce = 0++# Rated arena matches config+# MaxRatingDifference: the maximum rating difference between two groups in rated matches+# Default: 0 (disable, rating difference is discarded)  +# RatingDiscardTimer: after the specified milliseconds has passed, rating information will be discarded when selecting teams for matches+# also initiates an update by this timer+# Default: 60000+# AutoDistributePoints: set if arena points should be distributed weekly automatically, or by GM command+# Default: 0 (disable) (recommended): use gm command or sql query to distribute the points+#          1 (enable): arena points are distributed automatically+Arena.MaxRatingDifference = 0+Arena.RatingDiscardTimer = 60000+Arena.AutoDistributePoints = 0Index: src/shared/Database/DBCfmt.cpp===================================================================--- src/shared/Database/DBCfmt.cpp	(revision 5306)+++ src/shared/Database/DBCfmt.cpp	(working copy)@@ -42,7 +42,8 @@ const char GtRegenHPPerSptfmt[]="f"; const char GtRegenMPPerSptfmt[]="f"; const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx";-const char ItemExtendedCostEntryfmt[]="niiiiixxiiixxx";+const char ItemCondExtCostsEntryfmt[]="xiii";+const char ItemExtendedCostEntryfmt[]="niiiiixxiiixxi"; const char ItemRandomPropertiesfmt[]="nxiiixxxxxxxxxxxxxxxxxxx"; const char ItemRandomSuffixfmt[]="nxxxxxxxxxxxxxxxxxxiiiiii"; const char ItemSetEntryfmt[]="dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii";Index: src/shared/Database/DBCStores.cpp===================================================================--- src/shared/Database/DBCStores.cpp	(revision 5306)+++ src/shared/Database/DBCStores.cpp	(working copy)@@ -66,6 +66,7 @@  DBCStorage <ItemSetEntry> sItemSetStore(ItemSetEntryfmt); //DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt); -- not used currently+DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt); DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt); DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomPropertiesfmt); DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt);@@ -170,7 +171,7 @@ {     std::string tmpPath=""; -    const uint32 DBCFilesCount = 48;+    const uint32 DBCFilesCount = 49;      barGoLink bar( DBCFilesCount ); @@ -230,6 +231,7 @@     LoadDBC(bar,bad_dbc_files,sGtRegenMPPerSptStore,     dataPath+"dbc/gtRegenMPPerSpt.dbc");      //LoadDBC(bar,bad_dbc_files,sItemDisplayInfoStore,     dataPath+"dbc/ItemDisplayInfo.dbc");     -- not used currently+    LoadDBC(bar,bad_dbc_files,sItemCondExtCostsStore,    dataPath+"dbc/ItemCondExtCosts.dbc");     LoadDBC(bar,bad_dbc_files,sItemExtendedCostStore,    dataPath+"dbc/ItemExtendedCost.dbc");     LoadDBC(bar,bad_dbc_files,sItemRandomPropertiesStore,dataPath+"dbc/ItemRandomProperties.dbc");     LoadDBC(bar,bad_dbc_files,sItemRandomSuffixStore,    dataPath+"dbc/ItemRandomSuffix.dbc");@@ -542,6 +544,19 @@     return sTalentTabPages[cls]; } +uint32 GetItemCondExtCostsMask(uint32 requiredarenarank, uint32 itemextendedcost)+{+    // create and return mask for (RequiredArenaRank, ItemExtendedCost) pair+    uint32 mask = 0;+    for(uint32 i = 0; i < sItemCondExtCostsStore.nCount; ++i)+    {+        ItemCondExtCostsEntry const* icece = sItemCondExtCostsStore.LookupEntry(i);+        if(icece && icece->requiredarenarank == requiredarenarank && icece->itemextendedcostentry == itemextendedcost)+            mask |= (1 << icece->requirementtype);+    }+    return mask;+}+ // script support functions MANGOS_DLL_SPEC DBCStorage <SpellEntry>      const* GetSpellStore()      { return &sSpellStore;      } MANGOS_DLL_SPEC DBCStorage <SpellRangeEntry> const* GetSpellRangeStore() { return &sSpellRangeStore; }Index: src/shared/Database/DBCStores.h===================================================================--- src/shared/Database/DBCStores.h	(revision 5306)+++ src/shared/Database/DBCStores.h	(working copy)@@ -44,6 +44,7 @@ uint32 GetTalentInspectBitPosInTab(uint32 talentId); uint32 GetTalentTabInspectBitSize(uint32 talentTabId); uint32 const* /*[3]*/ GetTalentTabPages(uint32 cls);+uint32 GetItemCondExtCostsMask(uint32 requiredarenarank, uint32 itemextendedcost);  template<class T> class DBCStorageIndex: src/shared/Database/DBCStructure.h===================================================================--- src/shared/Database/DBCStructure.h	(revision 5306)+++ src/shared/Database/DBCStructure.h	(working copy)@@ -283,6 +283,16 @@     uint32      randomPropertyChance; }; +struct ItemCondExtCostsEntry+{+    // uint32      ID;+    uint32      requiredarenarank;                          // ItemPrototype::RequiredArenaRank+    uint32      itemextendedcostentry;                      // ItemPrototype::ExtendedCost+    uint32      requirementtype;                            // 1 - honor and/or arena point from itemextendedcost+                                                            // 2 - required item(s) from itemextendedcost+                                                            // 3 - required personal arena rating from itemextendedcost+};+ struct ItemExtendedCostEntry {     uint32      ID;                                         // 0 extended-cost entry id@@ -296,7 +306,7 @@     uint32      reqitemcount2;                              // 9 required count of 2st item     uint32      reqitemcount3;                              // 10 required count of 3st item                                                             // 11-12 not used, always 0 (4-5 item count?)-                                                            // 13 not used+    uint32      reqpersonalarenarating;                     // 13 required personal arena rating };  struct ItemRandomPropertiesEntry