All pastes #947765 Raw Edit

Untitled

public text v1 · immutable
·published 2008-03-18 18:25 UTC
rendered paste body
'Index: configure.ac
===================================================================
--- configure.ac	(revision 5447)
+++ configure.ac	(working copy)
@@ -228,7 +228,10 @@
    src/mangosd/Makefile
    src/mangosd/mangosd.conf
    src/bindings/Makefile
-   src/bindings/universal/Makefile
+   src/bindings/ScriptDev2/Makefile
+   src/bindings/ScriptDev2/config.h
+   src/bindings/ScriptDev2/sql/Makefile
+   src/bindings/ScriptDev2/sql/Updates/Makefile
 ])
 
 ## Disabled Makefiles, until they are ready for a successful make and
Index: src/bindings/Makefile.am
===================================================================
--- src/bindings/Makefile.am	(revision 5447)
+++ src/bindings/Makefile.am	(working copy)
@@ -14,4 +14,4 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-SUBDIRS = universal
+SUBDIRS = ScriptDev2
Index: src/game/ArenaTeam.cpp
===================================================================
--- src/game/ArenaTeam.cpp	(revision 5447)
+++ 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;
@@ -130,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));
@@ -138,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
@@ -207,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;
 
@@ -221,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;
@@ -279,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)
@@ -312,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);
@@ -390,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);
@@ -397,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);
 }
 
@@ -478,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 5447)
+++ 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/BattleGround.cpp
===================================================================
--- src/game/BattleGround.cpp	(revision 5447)
+++ 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
@@ -948,3 +1216,28 @@
     if(uint32 spellId = obj->GetGOInfo()->trap.spellId)
         source->CastSpell(source, spellId, true);
 }
+
+// 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 5447)
+++ 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,17 +369,18 @@
         // 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);
@@ -362,6 +388,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();
@@ -392,6 +423,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
@@ -417,6 +450,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 5447)
+++ 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 5447)
+++ 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 5447)
+++ 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,5 @@
 
 
 
+
+
Index: src/game/BattleGroundAB.h
===================================================================
--- src/game/BattleGroundAB.h	(revision 5447)
+++ 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 5447)
+++ 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 5447)
+++ 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 5447)
+++ src/game/BattleGroundBE.cpp	(working copy)
@@ -89,6 +89,10 @@
                 if(plr)
                     plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
             }
+			if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
+                EndBattleGround(HORDE);
+            else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
+                EndBattleGround(ALLIANCE);
         }
     }
 
@@ -98,9 +102,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 +113,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,14 +133,15 @@
         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(HORDE);
+     }
+    else if(!GetAlivePlayersCountByTeam(HORDE))
     {
         // all opponents killed
-        EndBattleGround(killer->GetTeam());
+        EndBattleGround(ALLIANCE);
     }
 }
 
@@ -141,14 +152,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,14 +167,13 @@
             break;
     }
 
-    if(buff_guid)
-        HandleTriggerBuff(buff_guid,Source);
+    if(obj)
+		HandleTriggerBuff(obj->GetGUID(),Source);
 }
 
 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 5447)
+++ 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
 };
 #endif
Index: src/game/BattleGroundEY.cpp
===================================================================
--- src/game/BattleGroundEY.cpp	(revision 5447)
+++ 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 5447)
+++ 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 5447)
+++ 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 5447)
+++ src/game/BattleGroundMgr.cpp	(working copy)
@@ -30,9 +30,11 @@
 #include "SharedDefines.h"
 #include "Policies/SingletonImp.h"
 #include "MapManager.h"
+#include "MapInstanced.h"
 #include "ObjectMgr.h"
 #include "ProgressBar.h"
 #include "World.h"
+#include "ArenaTeam.h"
 
 INSTANTIATE_SINGLETON_1( BattleGroundMgr );
 
@@ -43,12 +45,12 @@
 BattleGroundQueue::BattleGroundQueue()
 {
     //queues are empty, we don't have to call clear()
-    for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
-    {
-        m_QueuedPlayers[i].Horde = 0;
-        m_QueuedPlayers[i].Alliance = 0;
-        //m_QueuedPlayers[i].AverageTime = 0;
-    }
+/*    for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
+     {
+        //m_QueuedPlayers[i].Horde = 0;
+        //m_QueuedPlayers[i].Alliance = 0;
+         //m_QueuedPlayers[i].AverageTime = 0;
+     }*/
 }
 
 BattleGroundQueue::~BattleGroundQueue()
@@ -56,35 +58,188 @@
     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,227 @@
             }
         }
     }
-    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 +505,299 @@
     }
 
     //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();)
-                {
-                    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;
-                    }
+                // 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())
+				{
+                    // 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();
+            }
+        }
+    }
+ 
+    // finished iterating through the bgs with free slots, maybe we need to create a new bg
 
-                        // remove him from time queue
-                        itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
+    BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
+    if(!bg_template)
+    {
+        sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
+        return;
+    }
 
-                        // 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;
+    // 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;
+        }
+    }
 
-                        // 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());
+    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();
 
-                            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;
+    // 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 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
-                    }
-                }
+    // 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)
+         {
+            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)
         {
-            Player* plr = objmgr.GetPlayer(*itr2);
-            if (!plr)
+            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);
+            }
+            // 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);
+            }
+            bg2->StartBattleGround(0);
 
-                    sBattleGroundMgr.InvitePlayer(plr, bg2->GetInstanceID());
-
-                    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);
     }
 }
 
@@ -330,16 +820,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, INVITE_ACCEPT_WAIT_TIME/2, 0);
+                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, BG_REMIND_INVITE_TIME, 0);
                 plr->GetSession()->SendPacket(&data);
             }
         }
@@ -366,17 +857,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 +890,77 @@
 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();
 }
 
 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 +974,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 +1007,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,8 +1017,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 +1051,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 +1082,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 +1172,135 @@
     *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(INVITE_ACCEPT_WAIT_TIME/2));
-    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(INVITE_ACCEPT_WAIT_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
@@ -672,7 +1335,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);
@@ -684,9 +1347,10 @@
     //add BaggleGround instance to FreeSlotQueue
     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()
@@ -805,7 +1469,86 @@
     sLog.outString();
     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 `characters` b, `arena_team_member` a SET b.`data` = CONCAT( SUBSTRING_INDEX(b.`data`, ' ', '%u'),' ', CAST( IF ( ((CAST( SUBSTRING( b.`data` FROM (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) + 2) FOR (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) - CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) - 1) ) AS UNSIGNED) + (SELECT MAX(c.`points_to_add`) FROM `arena_team_member` c WHERE c.`guid` = b.`guid` GROUP BY c.`guid`) ) < '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 `characters` 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 +1584,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 +1616,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 5447)
+++ src/game/BattleGroundMgr.h	(working copy)
@@ -34,51 +34,99 @@
 
 #define MAX_BATTLEGROUND_TYPES 9                            // each BG type will be in array
 
-struct PlayerQueueInfo
+#define MAX_BATTLEGROUND_QUEUE_TYPES 8
+
+#define BG_REMIND_INVITE_TIME 60000                         // when this time pass, player get invitation request again
+
+#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);
 };
 
 /*
@@ -116,7 +164,6 @@
         uint32 m_PlayersTeam;
 };
 
-
 class BattleGroundMgr
 {
     public:
@@ -132,18 +179,17 @@
         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())
@@ -152,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 5447)
+++ 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,7 +86,13 @@
                 if(plr)
                     plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
             }
-        }
+        
+            if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
+                EndBattleGround(HORDE);
+            else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
+                EndBattleGround(ALLIANCE);
+
+		}
     }
 
     /*if(GetStatus() == STATUS_IN_PROGRESS)
@@ -92,9 +101,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 +112,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)
@@ -116,16 +131,16 @@
         sLog.outError("BattleGroundNA: Killer player not found");
         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,14 +164,13 @@
             break;
     }
 
-    if(buff_guid)
-        HandleTriggerBuff(buff_guid,Source);
+    if(obj)
+		HandleTriggerBuff(obj->GetGUID(),Source);
 }
 
 void BattleGroundNA::ResetBGSubclass()
 {
-    m_TeamKills[BG_TEAM_ALLIANCE] = 0;
-    m_TeamKills[BG_TEAM_HORDE]    = 0;
+    
 }
 
 bool BattleGroundNA::SetupBattleGround()
@@ -162,7 +179,11 @@
     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 5447)
+++ 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
 };
 #endif
Index: src/game/BattleGroundRL.cpp
===================================================================
--- src/game/BattleGroundRL.cpp	(revision 5447)
+++ src/game/BattleGroundRL.cpp	(working copy)
@@ -73,6 +73,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);
@@ -83,6 +86,10 @@
                 if(plr)
                     plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
             }
+			if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
+                EndBattleGround(HORDE);
+            else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
+                EndBattleGround(ALLIANCE);
         }
     }
 
@@ -92,9 +99,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;
 
@@ -103,7 +110,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)
@@ -117,15 +130,15 @@
         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)
@@ -135,11 +148,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);
@@ -147,21 +163,23 @@
             break;
     }
 
-    if(buff_guid)
-        HandleTriggerBuff(buff_guid,Source);
+    if(obj)
+		HandleTriggerBuff(obj->GetGUID(),Source);
 }
 
 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 5447)
+++ 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
 };
 #endif
Index: src/game/BattleGroundWS.cpp
===================================================================
--- src/game/BattleGroundWS.cpp	(revision 5447)
+++ src/game/BattleGroundWS.cpp	(working copy)
@@ -50,12 +50,16 @@
         {
             m_Events |= 0x01;
 
-            for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++)
-                SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+            for(uint32 i = WS_SPIRIT_MAIN_ALLIANCE; i <= WS_SPIRIT_MAIN_HORDE; i++)
+               SpawnBGCreature(i, RESPAWN_IMMEDIATELY);
 
             for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++)
                 SpawnBGObject(i, RESPAWN_ONE_DAY);
 
+            //doors
+            for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++)
+                SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+
             SetStartDelayTime(START_DELAY0);
         }
         // After 1 minute, warning is signalled
@@ -74,17 +78,9 @@
         else if(GetStartDelayTime() < 0 && !(m_Events & 0x10))
         {
             m_Events |= 0x10;
-            for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_4; i++)
-                DoorOpen(i);
+            for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++)
+                SpawnBGObject(i, RESPAWN_ONE_DAY);
 
-            for(uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_2; i++)
-                DoorOpen(i);
-
-            SpawnBGObject(BG_WS_OBJECT_DOOR_A_5, RESPAWN_ONE_DAY);
-            SpawnBGObject(BG_WS_OBJECT_DOOR_A_6, RESPAWN_ONE_DAY);
-            SpawnBGObject(BG_WS_OBJECT_DOOR_H_3, RESPAWN_ONE_DAY);
-            SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY);
-
             for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++)
                 SpawnBGObject(i, RESPAWN_IMMEDIATELY);
 
@@ -119,9 +115,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;
 
@@ -402,7 +398,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().
@@ -445,7 +441,7 @@
     }
 
     if(buff_guid)
-        HandleTriggerBuff(buff_guid,Source);
+		HandleTriggerBuff(buff_guid->GetGUID(),Source);	
 }
 
 bool BattleGroundWS::SetupBattleGround()
@@ -506,13 +502,13 @@
     m_TeamScores[BG_TEAM_ALLIANCE]      = 0;
     m_TeamScores[BG_TEAM_HORDE]         = 0;
 
-    if(m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE])
+    /*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)
 {
     if(GetStatus() != STATUS_IN_PROGRESS)
@@ -550,7 +546,6 @@
             break;
     }
 }
-
 void BattleGroundWS::FillInitialWorldStates(WorldPacket& data)
 {
     data << uint32(BG_WS_FLAG_CAPTURES_ALLIANCE) << uint32(GetTeamScore(ALLIANCE));
Index: src/game/BattleGroundWS.h
===================================================================
--- src/game/BattleGroundWS.h	(revision 5447)
+++ 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/Channel.cpp
===================================================================
--- src/game/Channel.cpp	(revision 5447)
+++ src/game/Channel.cpp	(working copy)
@@ -98,7 +98,7 @@
     if(m_announce && (!plr || plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL) ))
     {
         MakeJoined(&data, p);
-        SendToAll(&data);
+        //SendToAll(&data);
     }
 
     data.clear();
@@ -111,7 +111,7 @@
     MakeYouJoined(&data);
     SendToOne(&data, p);
 
-    JoinNotify(p);
+    //JoinNotify(p);
 
     // if no owner first logged will become
     if(!IsConstant() && !m_ownerGUID)
@@ -153,10 +153,10 @@
         {
             WorldPacket data;
             MakeLeft(&data, p);
-            SendToAll(&data);
+            //SendToAll(&data);
         }
 
-        LeaveNotify(p);
+        //LeaveNotify(p);
 
         if(changeowner)
         {
Index: src/game/Chat.cpp
===================================================================
--- src/game/Chat.cpp	(revision 5447)
+++ 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 5447)
+++ 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/Language.h
===================================================================
--- src/game/Language.h	(revision 5447)
+++ 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 VALUES
Index: src/game/Level3.cpp
===================================================================
--- src/game/Level3.cpp	(revision 5447)
+++ src/game/Level3.cpp	(working copy)
@@ -43,6 +43,7 @@
 #include "SkillExtraItems.h"
 #include "SystemConfig.h"
 #include "Config/ConfigEnv.h"
+#include "BattleGroundMgr.h"
 
 //reload commands
 bool ChatHandler::HandleReloadCommand(const char* arg)
@@ -4747,3 +4748,9 @@
 
     return true;
 }
+
+bool ChatHandler::HandleFlushArenaPointsCommand(const char * /*args*/)
+{
+    sBattleGroundMgr.DistributeArenaPoints();
+    return true;
+}
Index: src/game/Map.cpp
===================================================================
--- src/game/Map.cpp	(revision 5447)
+++ 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 5447)
+++ 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);
@@ -208,7 +210,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)); }
@@ -294,6 +296,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 5447)
+++ src/game/MapInstanced.cpp	(working copy)
@@ -44,6 +44,7 @@
         {
             if (!i->second->HavePlayers())
             {
+                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 5447)
+++ 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 5447)
+++ src/game/MovementHandler.cpp	(working copy)
@@ -102,17 +102,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());
                 }
             }
         }
@@ -519,3 +523,16 @@
 }
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: src/game/Player.cpp
===================================================================
--- src/game/Player.cpp	(revision 5447)
+++ src/game/Player.cpp	(working copy)
@@ -334,7 +334,7 @@
         ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race);
         if(!rEntry)
         {
-            sLog.outError("Race %u not found in DBŃ (Wrong DBC files?)",race);
+            sLog.outError("Race %u not found in DB?(Wrong DBC files?)",race);
             return false;
         }
 
@@ -1258,8 +1258,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;
@@ -1442,7 +1442,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();
@@ -1602,7 +1602,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
@@ -2734,6 +2735,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())
@@ -5543,6 +5570,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->HasAuraType(SPELL_AURA_NO_PVP_CREDIT))
@@ -5814,7 +5845,7 @@
     // flags & 0x00004000   (16384) - outland zones? (only Circle of Blood Arena not have this flag, but have 0x00000400 flag)
     // flags & 0x00008000   (32768) - pvp objective area?
 
-    if((zone->flags & 0x800) != 0)                          // in sanctuary
+    if((zone->flags & 0x800) != 0 || (GetAreaId() == 976) || (GetAreaId() == 35) || (GetAreaId() == 392) || (GetAreaId() == 2255))                          // in sanctuary
     {
         UpdatePvP(false, true);                             // i'm right? need disable PvP in this area...
 
@@ -8740,6 +8771,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
 
@@ -8867,6 +8905,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;
 
@@ -9911,6 +9956,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)
@@ -16245,7 +16338,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 5447)
+++ src/game/Player.h	(working copy)
@@ -863,7 +863,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)
         {
@@ -1044,6 +1044,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 );
@@ -1352,6 +1353,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();
@@ -1719,9 +1721,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;
@@ -1868,6 +1872,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 5447)
+++ src/game/Spell.cpp	(working copy)
@@ -1497,6 +1497,14 @@
 {
     m_targets = *targets;
 
+	//only intialize Auto-Repeat spell with target, further handling in Unit::_UpdateAutoRepeatspells
+	if (m_autoRepeat && m_caster->m_AutoRepeatFirstCast)
+	{	
+		m_spellState = SPELL_STATE_IDLE;
+		m_caster->SetCurrentCastedSpell( this );
+        return;
+	}
+
     m_spellState = SPELL_STATE_PREPARING;
 
     m_castPositionX = m_caster->GetPositionX();
@@ -1551,16 +1559,15 @@
         m_caster->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
     }
 
-    // do first cast of autorepeat spell with recovery time delay (like after any autocast)
-    if(IsAutoRepeat())
-        m_spellState = SPELL_STATE_FINISHED;
-
     if(m_IsTriggeredSpell)
         cast(true);
     else
     {
         m_caster->SetCurrentCastedSpell( this );
         m_selfContainer = &(m_caster->m_currentSpells[GetCurrentContainer()]);
+
+		if (m_autoRepeat) return; //graphics for autorepeat spells handled in Unit::_UpdateAutoRepeatSpells
+
         SendSpellStart();
     }
 }
@@ -1579,6 +1586,9 @@
             SendInterrupted(0);
             SendCastResult(SPELL_FAILED_INTERRUPTED);
         } break;
+		
+		case SPELL_STATE_IDLE: //Auto-Repeat spells
+			SendInterrupted(0); break;
 
         case SPELL_STATE_CASTING:
         {
@@ -1897,9 +1907,9 @@
         catrec = m_spellInfo->CategoryRecoveryTime;
     }
 
-    // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
+    // shoot spells (not wand shoot, for easier handling in Unit::_UpdateAutoRepeatSpell) used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
     // prevent 0 cooldowns set by another way
-    if (rec <= 0 && catrec <= 0 && (cat == 76 || cat == 351))
+    if (rec <= 0 && catrec <= 0 && (cat == 76))
         rec = _player->GetAttackTime(RANGED_ATTACK);
 
     // Now we have cooldown data (if found any), time to apply mods
@@ -1962,23 +1972,10 @@
     // update pointers based at it's GUIDs
     UpdatePointers();
 
-    if(m_targets.getUnitTargetGUID())
+	if(m_targets.getUnitTargetGUID() && !m_targets.getUnitTarget())
     {
-        if(!m_targets.getUnitTarget() || !m_targets.getUnitTarget()->isAlive())
-        {
-            if(m_autoRepeat)
-            {
-                m_autoRepeat = false;
-                m_spellState = SPELL_STATE_FINISHED;
-                return;
-            }
-
-            if(!m_targets.getUnitTarget())
-            {
-                cancel();
-                return;
-            }
-        }
+		cancel();
+		return;
     }
 
     // check if the player caster has moved before the spell finished
@@ -1989,8 +1986,8 @@
         // always cancel for channeled spells
         if( m_spellState == SPELL_STATE_CASTING )
             cancel();
-        // don't cancel for melee, autorepeat and instant spells
-        else if(!m_meleeSpell && !m_autoRepeat && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))
+        // don't cancel for melee, autoshot(not wand shoot) and instant spells
+        else if(!m_meleeSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) || m_spellInfo->Category == 351)
             cancel();
     }
 
@@ -2007,7 +2004,7 @@
             }
 
             if(m_timer == 0 && !m_meleeSpell)
-                cast();
+                cast(m_autoRepeat); //skip check for Auto-Repeat Spells, already checked in Unit::_UpdateAutoRepeatSpells
         } break;
         case SPELL_STATE_CASTING:
         {
@@ -2557,12 +2554,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
@@ -2778,6 +2783,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();
 
@@ -3768,6 +3782,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)
@@ -3775,26 +3792,35 @@
 
         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/SpellEffects.cpp
===================================================================
--- src/game/SpellEffects.cpp	(revision 5447)
+++ src/game/SpellEffects.cpp	(working copy)
@@ -1346,11 +1346,14 @@
         // Scatter Shot
         case 37506:
         {
-            if (m_caster->GetTypeId()!=TYPEID_PLAYER)
+            // break Auto Shot and "Attack"
+			m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+			m_caster->AttackStop();
+			
+			if (m_caster->GetTypeId()!=TYPEID_PLAYER)
                 return;
-
-            // break Auto Shot
-            m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+   			
+			((Player*)m_caster)->SendAttackSwingCancelAttack(); //force autoshot cancel
             return;
         }
 
Index: src/game/SpellHandler.cpp
===================================================================
--- src/game/SpellHandler.cpp	(revision 5447)
+++ 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)
@@ -469,7 +478,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)
@@ -484,7 +494,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)
@@ -715,7 +726,6 @@
 
 void WorldSession::HandleCancelAutoRepeatSpellOpcode( WorldPacket& /*recvPacket*/)
 {
-    // may be better send SMSG_CANCEL_AUTO_REPEAT?
     // cancel and prepare for deleting
     _player->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
 }
Index: src/game/Unit.cpp
===================================================================
--- src/game/Unit.cpp	(revision 5447)
+++ src/game/Unit.cpp	(working copy)
@@ -212,6 +212,8 @@
     m_charmInfo = NULL;
     m_moveRun = false;
 
+	m_AutoRepeatFirstCast = true;
+
     // remove aurastates allowing special moves
     for(int i=0; i < MAX_REACTIVE; ++i)
         m_reactiveTimer[i] = 0;
@@ -410,14 +412,16 @@
 }
 
 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
-void Unit::RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage)
+void Unit::RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage, uint32 casterLevel)
 {
     if(!HasAuraType(auraType))
         return;
 
     // The chance to dispell an aura depends on the damage taken with respect to the casters level.
     uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
-    float chance = float(damage) / max_dmg * 100.0f;
+    float chanceDamage = float(damage) / max_dmg * 100.0f * 0.67f;
+    float chanceLevel = float(casterLevel) / getLevel() * 100 * 0.33f;
+    float chance = chanceDamage + chanceLevel;
     if (roll_chance_f(chance))
         RemoveSpellsCausingAura(auraType);
 }
@@ -469,10 +473,10 @@
         return;
     }
 
-    pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage);
+    pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage, getLevel());
     // root type spells do not dispell the root effect
     if(!spellProto || spellProto->Mechanic != MECHANIC_ROOT)
-        pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage);
+        pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage, getLevel());
 
     if(pVictim->GetTypeId() != TYPEID_PLAYER)
     {
@@ -570,36 +574,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");
@@ -845,6 +819,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)
     {
@@ -3266,94 +3273,132 @@
 
 void Unit::_UpdateAutoRepeatSpell()
 {
-    if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_FINISHED)
-    {
-        //Auto Shot & Shoot
-        if( m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->AttributesEx2 == 0x000020 && GetTypeId() == TYPEID_PLAYER )
-        {
-            // Auto Shot don't require ranged weapon cooldown at first cast, wand shoot does, so the 'FINISHED' state
-            if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
-            {
-                // Shoot
-                resetAttackTimer( RANGED_ATTACK );
-            }
-            else
-            {
-                // Auto Shoot
-                if (m_AutoRepeatFirstCast)
-                {
-                    // first cast only with recovery time (not less)
-                    if (getAttackTimer( RANGED_ATTACK ) < m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime)
-                        setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime);
-                    m_AutoRepeatFirstCast = false;
-                }
-                else
-                {
-                    // second or further casts
-                    resetAttackTimer( RANGED_ATTACK );
-                }
-            }
-        }
-        else
-        {
-            setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime);
-        }
+ if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE )
+	{	
+		//update the spell's pointers and check the target (not done in spell:update for autorepeat spells)
+		m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->UpdatePointers();
+		if ( !(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTargetGUID() &&
+			m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTarget() &&
+			m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTarget()->isAlive()))
+		{
+			InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+			if(GetTypeId()==TYPEID_PLAYER)
+				((Player*)this)->SendAttackSwingCancelAttack(); //force autoshot cancel
+			
+			return;
+		}
+			
+		
+		//on First cast we need a prepare animation	
+		if(m_AutoRepeatFirstCast) m_AutoRepeatSpellStart =true;
+	
+		uint8 result = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true);
+        // CanCast check
+		if (result)
+		{			            	
+			// cancel wand shooting and send result
+			if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
+			{	
+				m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendCastResult(result);
+				InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+				return;
+			}
+			
+			//else...don't cancel "autoshot" and send result, if "cooldown" is over; except "moving"
+			if (isAttackReady(RANGED_ATTACK) && result!= SPELL_FAILED_MOVING)
+				m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendCastResult(result);
+				
+			//if interruption is during the prepare animation we additionally need to stop animation
+			if (getAttackTimer(RANGED_ATTACK)<=500 && !m_AutoRepeatFirstCast)
+			{
+				m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendInterrupted(0);
+			}
+			//now we need again our 0.5 sec....
+			m_AutoRepeatFirstCast = true;
+				
+		}
+		
+		//...we CanCast, now check if we are castig melee spell, or anything else	
+		else if (	(m_currentSpells[CURRENT_MELEE_SPELL] &&
+						(m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_FINISHED) &&
+						(m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_DELAYED)
+					)	||	
+					IsNonMeleeSpellCasted(false, false, true)
+				)
+		{
+			//...of course we need again time to aim ....
+			m_AutoRepeatFirstCast = true;
+		}
+		
+		else //ok, nothing casting currently
+		{ 
+			//handling the 0.5s
+			if(m_AutoRepeatFirstCast == true && getAttackTimer(RANGED_ATTACK) < 500) 
+			{	
+				setAttackTimer(RANGED_ATTACK, 500);
+			}
+			
+			m_AutoRepeatFirstCast = false;
+			
+			// handle graphics, 0.5sec of preparing (blizz-like) 
+			 if( getAttackTimer(RANGED_ATTACK) <= 500 && m_AutoRepeatSpellStart)
+			{
+				m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendSpellStart();
+				m_AutoRepeatSpellStart = false;
+			}
+			
+			//now we got it, ...nearly :-) 
+			else if(isAttackReady(RANGED_ATTACK) && result != SPELL_FAILED_NOT_READY ) 
+			{
+				// recheck CanCast() to avoid interruption problems in Spell::prepare
+				if(result = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true) == 0 )
+				{
+					// start the spell
+					m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
+					resetAttackTimer( RANGED_ATTACK ); 
+				}
+				else 
+				{	//the well known procedure...
+					if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
+					{	
+						m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendCastResult(result);
+						InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+					}
+					else m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SendInterrupted(0); //break prepare animation
+					
+					m_AutoRepeatFirstCast = true;
+				}
+			 }
+		}
+	}
+	
+	else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_DELAYED)
+	{   
+		m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->UpdatePointers();
 
-        m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);
-    }
-    else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE && isAttackReady(RANGED_ATTACK) )
-    {
-        // check if we can cast
-        if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true) == 0)
-        {
-            // check movement in player case
-            if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving())
-            {
-                // cancel wand shooting
-                if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
-                    InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
-                // ELSE delay auto-repeat ranged weapon until player movement stop
-            }
-            else
-                // recheck range and req. items (ammo and gun, etc)
-            if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckRange(true) == 0 && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckItems() == 0 )
-            {
-                // check, if we are casting melee spell (it blocks autorepeat)
-                if ( ! (m_currentSpells[CURRENT_MELEE_SPELL] &&
-                    (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_FINISHED) &&
-                    (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_DELAYED)) )
-                {
-                    // check, if we are casting something else, if no then run autorepeat spell
-                    if (!IsNonMeleeSpellCasted(false, false, true))
-                    {
-                        m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_PREPARING);
-                        m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->ReSetTimer();
-                    }
-                }
-            }
-            else
-            {
-                InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
-            }
-        }
-        else
-        {
-            InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
-        }
-    }
-    else if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_PREPARING)
-    {
-        // check, if some other incomplete spell exists (including melee) or ranged attack is not ready
-        if ( m_currentSpells[CURRENT_MELEE_SPELL] ||
-            m_currentSpells[CURRENT_GENERIC_SPELL] ||
-            m_currentSpells[CURRENT_CHANNELED_SPELL] ||
-            !isAttackReady(RANGED_ATTACK) )
-        {
-            // some other spell is here or ranged attack is not ready, break us to idle state
-            m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->finish(false);
-            m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);
-        }
-    }
+		//check if target is still ok
+		if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTargetGUID() &&
+			m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTarget() &&
+			m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets.getUnitTarget()->isAlive())
+		{
+			//store spell information
+			SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id);
+        
+			m_AutoRepeatFirstCast = true;
+			m_AutoRepeatSpellStart = true;
+
+			//create and intialize new spell with old target
+			Spell *p_spell = new Spell(this, spellInfo, false, 0);
+			p_spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
+		}
+		else //target not exist....?
+		{
+			InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+			if(GetTypeId()==TYPEID_PLAYER)
+				((Player*)this)->SendAttackSwingCancelAttack(); //force autoshot cancel
+
+		}
+	}	
 }
 
 void Unit::SetCurrentCastedSpell( Spell * pSpell )
@@ -3390,6 +3435,9 @@
                 // break autorepeat if not Auto Shot
                 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
                     InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
+				
+				//new casttime for autoshot
+				m_AutoRepeatFirstCast = true;
             }
         } break;
 
@@ -3413,12 +3461,7 @@
                 // generic autorepeats break generic and channeled spells
                 InterruptSpell(CURRENT_GENERIC_SPELL);
                 InterruptSpell(CURRENT_CHANNELED_SPELL);
-            }
-            else
-            {
-                // special action: set first cast flag for Auto Shoot
-                m_AutoRepeatFirstCast = true;
-            }
+            }           
         } break;
 
         default:
@@ -3441,13 +3484,10 @@
 
     if(m_currentSpells[spellType])
     {
-        // send autorepeat cancel message for autorepeat spells
-        if (spellType == CURRENT_AUTOREPEAT_SPELL)
-        {
-            if(GetTypeId()==TYPEID_PLAYER)
-                ((Player*)this)->SendAutoRepeatCancel();
-        }
+        // set first cast for autorepeat spells
+        if (spellType == CURRENT_AUTOREPEAT_SPELL)	m_AutoRepeatFirstCast = true;
 
+
         if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED)
             m_currentSpells[spellType]->cancel();
         m_currentSpells[spellType]->SetDeletable(true);
@@ -3493,9 +3533,7 @@
     // autorepeat spells are interrupted if they are not finished or delayed
     if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
     {
-        // send disable autorepeat packet in any case
-        if(GetTypeId()==TYPEID_PLAYER)
-            ((Player*)this)->SendAutoRepeatCancel();
+        m_AutoRepeatFirstCast = true;
 
         if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) &&
             (withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) )
@@ -4055,6 +4093,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 auras
Index: src/game/Unit.h
===================================================================
--- src/game/Unit.h	(revision 5447)
+++ src/game/Unit.h	(working copy)
@@ -755,7 +755,7 @@
 
         bool isFrozen() const;
 
-        void RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage);
+        void RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage, uint32 casterLevel);
 
         bool isTargetableForAttack() const;
         virtual bool IsInWater() const;
@@ -823,6 +823,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);
@@ -879,6 +880,7 @@
 
         float m_threatModifier[MAX_SPELL_SCHOOL];
         float m_modAttackSpeedPct[3];
+		bool m_AutoRepeatFirstCast;
 
         // Event handler
         EventProcessor m_Events;
@@ -1033,7 +1035,7 @@
         void _UpdateSpells(uint32 time);
 
         void _UpdateAutoRepeatSpell();
-        bool m_AutoRepeatFirstCast;
+        bool m_AutoRepeatSpellStart;
 
         uint32 m_attackTimer[MAX_ATTACK];
 
Index: src/game/World.cpp
===================================================================
--- src/game/World.cpp	(revision 5447)
+++ src/game/World.cpp	(working copy)
@@ -509,6 +509,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)
     {
@@ -846,6 +850,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 5447)
+++ src/game/World.h	(working copy)
@@ -120,6 +120,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/Makefile.am
===================================================================
--- src/mangosd/Makefile.am	(revision 5447)
+++ src/mangosd/Makefile.am	(working copy)
@@ -33,8 +33,8 @@
 	WorldRunnable.h
 
 ## Link world daemon against the shared library
-mangos_worldd_LDADD = ../bindings/universal/libmangosscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a  ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a
-mangos_worldd_LDFLAGS = -L../../dep/src/sockets -L../../dep/src/zthread -L../../dep/src/g3dlite -L../bindings/universal/ $(MYSQL_LIBS) $(POSTGRE_LIBS) -L$(libdir) $(ZLIB) $(COMPATLIB) $(SSLLIB) -export-dynamic
+mangos_worldd_LDADD = ../bindings/ScriptDev2/libmangosscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a  ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a
+mangos_worldd_LDFLAGS = -L../../dep/src/sockets -L../../dep/src/zthread -L../../dep/src/g3dlite -L../bindings/ScriptDev2/ $(MYSQL_LIBS) $(POSTGRE_LIBS) -L$(libdir) $(ZLIB) $(COMPATLIB) $(SSLLIB) -export-dynamic
 
 ## Additional files to include when running 'make dist'
 #  Include world daemon configuration
Index: src/mangosd/mangosd.conf.in
===================================================================
--- src/mangosd/mangosd.conf.in	(revision 5447)
+++ src/mangosd/mangosd.conf.in	(working copy)
@@ -556,7 +556,7 @@
 #    Visibility.Distance.Grey.Unit
 #        Visibility grey distance for creatures/players (fast changing objects)
 #        addition to appropriate object type Visibility.Distance.* use in case visibility removing to
-#        object (except corpse around distences) If ‚ is distance and G is grey distance then object
+#        object (except corpse around distences) If ?is distance and G is grey distance then object
 #        make visible if distance to it <= D but make non visible if distance > D+G
 #        Default: 1 (yard)
 #
@@ -761,3 +761,16 @@
 Ra.Port = 3443
 Ra.MinLevel = 3
 Ra.Secure = 1
+
+# 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 = 0