Index: src/shared/Database/DBCStructure.h
===================================================================
--- src/shared/Database/DBCStructure.h	(revision 6743)
+++ src/shared/Database/DBCStructure.h	(working copy)
@@ -471,9 +471,10 @@
 
     // Helpers
     bool IsExpansionMap() const { return addon != 0; }
-    bool Instanceable() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID; }
-    // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable
+
+
     bool IsDungeon() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID; }
+    bool Instanceable() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID || map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; }
     bool IsRaid() const { return map_type == MAP_RAID; }
     bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; }
     bool IsBattleArena() const { return map_type == MAP_ARENA; }
Index: src/mangosd/Makefile.am
===================================================================
--- src/mangosd/Makefile.am	(revision 6743)
+++ 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/game/SpellEffects.cpp
===================================================================
--- src/game/SpellEffects.cpp	(revision 6743)
+++ src/game/SpellEffects.cpp	(working copy)
@@ -48,6 +48,7 @@
 #include "BattleGround.h"
 #include "BattleGroundEY.h"
 #include "BattleGroundWS.h"
+#include "OutdoorPvPMgr.h"
 #include "VMapFactory.h"
 #include "Language.h"
 #include "SocialMgr.h"
@@ -2598,7 +2599,7 @@
                 return;
         }
 
-        if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType))
+        if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
             bg->SendRewardMarkByMail(player,newitemid,no_space);
     }
 }
@@ -2861,6 +2862,10 @@
                 return;
             }
         }
+        // handle outdoor pvp object opening, return true if go was registered for handling
+        // these objects must have been spawned by outdoorpvp!
+        else if(gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_GOOBER && sOutdoorPvPMgr.HandleOpenGo(player, gameObjTarget->GetGUID()))
+            return;
         lockId = gameObjTarget->GetLockId();
         guid = gameObjTarget->GetGUID();
     }
Index: src/game/OutdoorPvPSI.h
===================================================================
--- src/game/OutdoorPvPSI.h	(revision 0)
+++ src/game/OutdoorPvPSI.h	(revision 0)
@@ -0,0 +1,57 @@
+#ifndef OUTDOOR_PVP_SI_
+#define OUTDOOR_PVP_SI_
+
+#include "OutdoorPvP.h"
+
+const uint32 SI_SILITHYST_FLAG_GO_SPELL = 29518;
+
+const uint32 SI_SILITHYST_FLAG = 29519;
+
+const uint32 SI_TRACES_OF_SILITHYST = 29534;
+
+const uint32 SI_CENARION_FAVOR = 30754;
+
+const uint32 SI_MAX_RESOURCES = 200;
+
+const uint32 OutdoorPvPSIBuffZonesNum = 3;
+
+const uint32 OutdoorPvPSIBuffZones[OutdoorPvPSIBuffZonesNum] = { 1377, 3428, 3429 };
+
+const uint32 SI_AREATRIGGER_H = 4168;
+
+const uint32 SI_AREATRIGGER_A = 4162;
+
+const uint32 SI_TURNIN_QUEST_CM_A = 17090;
+
+const uint32 SI_TURNIN_QUEST_CM_H = 18199;
+
+const uint32 SI_SILITHYST_MOUND = 181597;
+
+enum SI_WorldStates{
+    SI_GATHERED_A = 2313,
+    SI_GATHERED_H = 2314,
+    SI_SILITHYST_MAX = 2317
+};
+
+class OutdoorPvPSI : public OutdoorPvP
+{
+public:
+    OutdoorPvPSI();
+    bool SetupOutdoorPvP();
+    void HandlePlayerEnterZone(Player *plr, uint32 zone);
+    void HandlePlayerLeaveZone(Player *plr, uint32 zone);
+    bool Update(uint32 diff);
+    void FillInitialWorldStates(WorldPacket &data);
+    void SendRemoveWorldStates(Player * plr);
+    bool HandleAreaTrigger(Player * plr, uint32 trigger);
+    bool HandleDropFlag(Player * plr, uint32 spellId);
+    bool HandleCustomSpell(Player * plr, uint32 spellId, GameObject *go);
+    void BuffTeam(uint32 team);
+    void UpdateWorldState();
+private:
+    uint32 m_Gathered_A;
+    uint32 m_Gathered_H;
+    uint32 m_LastController;
+};
+
+#endif
Index: src/game/Level3.cpp
===================================================================
--- src/game/Level3.cpp	(revision 6743)
+++ src/game/Level3.cpp	(working copy)
@@ -46,6 +46,7 @@
 #include "Config/ConfigEnv.h"
 #include "Util.h"
 #include "ItemEnchantmentMgr.h"
+#include "BattleGroundMgr.h"
 #include "InstanceSaveMgr.h"
 #include "InstanceData.h"
 
@@ -5457,3 +5458,9 @@
     ((InstanceMap*)map)->GetInstanceData()->SaveToDB();
     return true;
 }
+
+bool ChatHandler::HandleFlushArenaPointsCommand(const char * /*args*/)
+{
+    sBattleGroundMgr.DistributeArenaPoints();
+    return true;
+}
Index: src/game/OutdoorPvPNA.h
===================================================================
--- src/game/OutdoorPvPNA.h	(revision 0)
+++ src/game/OutdoorPvPNA.h	(revision 0)
@@ -0,0 +1,279 @@
+#ifndef OUTDOOR_PVP_NA_
+#define OUTDOOR_PVP_NA_
+
+// TODO: "sometimes" set to neutral
+
+#include "OutdoorPvP.h"
+
+// kill credit for pks
+const uint32 NA_CREDIT_MARKER = 24867;
+
+const uint32 NA_KILL_TOKEN_ALLIANCE = 33005;
+const uint32 NA_KILL_TOKEN_HORDE = 33004;
+
+const uint32 NA_CAPTURE_BUFF = 33795;  // strength of the halaani
+
+const uint32 NA_GUARDS_MAX = 15;
+
+const uint32 NA_BUFF_ZONE = 3518;
+
+const uint32 NA_HALAA_GRAVEYARD = 993;
+
+const uint32 NA_HALAA_GRAVEYARD_ZONE = 3518; // need to add zone id, not area id
+
+const uint32 NA_RESPAWN_TIME = 3600000; // one hour to capture after defeating all guards
+
+const uint32 NA_GUARD_CHECK_TIME = 500; // every half second
+
+enum OutdoorPvPNAWorldStates{
+    NA_UI_HORDE_GUARDS_SHOW = 2503,
+    NA_UI_ALLIANCE_GUARDS_SHOW = 2502,
+    NA_UI_GUARDS_MAX = 2493,
+    NA_UI_GUARDS_LEFT = 2491,
+
+    NA_UI_TOWER_SLIDER_DISPLAY = 2495,
+    NA_UI_TOWER_SLIDER_POS = 2494,
+    NA_UI_TOWER_SLIDER_N = 2497,
+
+    NA_MAP_WYVERN_NORTH_NEU_H = 2762,
+    NA_MAP_WYVERN_NORTH_NEU_A = 2662,
+    NA_MAP_WYVERN_NORTH_H = 2663,
+    NA_MAP_WYVERN_NORTH_A = 2664,
+
+    NA_MAP_WYVERN_SOUTH_NEU_H = 2760,
+    NA_MAP_WYVERN_SOUTH_NEU_A = 2670,
+    NA_MAP_WYVERN_SOUTH_H = 2668,
+    NA_MAP_WYVERN_SOUTH_A = 2669,
+
+    NA_MAP_WYVERN_WEST_NEU_H = 2761,
+    NA_MAP_WYVERN_WEST_NEU_A = 2667,
+    NA_MAP_WYVERN_WEST_H = 2665,
+    NA_MAP_WYVERN_WEST_A = 2666,
+
+    NA_MAP_WYVERN_EAST_NEU_H = 2763,
+    NA_MAP_WYVERN_EAST_NEU_A = 2659,
+    NA_MAP_WYVERN_EAST_H = 2660,
+    NA_MAP_WYVERN_EAST_A = 2661,
+
+    NA_MAP_HALAA_NEUTRAL = 2671,
+    NA_MAP_HALAA_NEU_A = 2676,
+    NA_MAP_HALAA_NEU_H = 2677,
+    NA_MAP_HALAA_HORDE = 2672,
+    NA_MAP_HALAA_ALLIANCE = 2673 
+};
+
+const uint32 FLIGHT_NODES_NUM = 4;
+
+// used to access the elements of Horde/AllyControlGOs
+enum ControlGOTypes{
+    NA_ROOST_S = 0,
+    NA_ROOST_W = 1,
+    NA_ROOST_N = 2,
+    NA_ROOST_E = 3,
+
+    NA_BOMB_WAGON_S = 4,
+    NA_BOMB_WAGON_W = 5,
+    NA_BOMB_WAGON_N = 6,
+    NA_BOMB_WAGON_E = 7,
+
+    NA_DESTROYED_ROOST_S = 8, 
+    NA_DESTROYED_ROOST_W = 9, 
+    NA_DESTROYED_ROOST_N = 10,
+    NA_DESTROYED_ROOST_E = 11,
+
+    NA_CONTROL_GO_NUM = 12
+};
+
+const uint32 FlightPathStartNodes[FLIGHT_NODES_NUM] = {103,105,107,109};
+const uint32 FlightPathEndNodes[FLIGHT_NODES_NUM] = {104,106,108,110};
+
+enum FlightSpellsNA{
+    NA_SPELL_FLY_SOUTH = 32059,
+    NA_SPELL_FLY_WEST = 32068,
+    NA_SPELL_FLY_NORTH = 32075,
+    NA_SPELL_FLY_EAST = 32081
+};
+
+// spawned when the alliance is attacking, horde is in control
+const go_type HordeControlGOs[NA_CONTROL_GO_NUM] = {
+    {182267,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //ALLY_ROOST_SOUTH
+    {182280,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //ALLY_ROOST_WEST
+    {182281,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //ALLY_ROOST_NORTH
+    {182282,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048}, //ALLY_ROOST_EAST
+
+    {182222,530,-1825.4022,8039.2602,-26.08,-2.89725,0,0,0.992546,-0.121869}, //HORDE_BOMB_WAGON_SOUTH
+    {182272,530,-1515.37,8136.91,-20.42,-1.3439,0,0,0.622515,-0.782608}, //HORDE_BOMB_WAGON_WEST
+    {182273,530,-1377.95,7773.44,-10.31,-0.575959,0,0,0.284015,-0.95882}, //HORDE_BOMB_WAGON_NORTH
+    {182274,530,-1659.87,7733.15,-15.75,-2.80998,0,0,0.986286,-0.165048}, //HORDE_BOMB_WAGON_EAST
+
+    {182266,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //DESTROYED_ALLY_ROOST_SOUTH
+    {182275,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //DESTROYED_ALLY_ROOST_WEST
+    {182276,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //DESTROYED_ALLY_ROOST_NORTH
+    {182277,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048}  //DESTROYED_ALLY_ROOST_EAST
+};
+
+// spawned when the horde is attacking, alliance is in control
+const go_type AllianceControlGOs[NA_CONTROL_GO_NUM] = {
+    {182301,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //HORDE_ROOST_SOUTH
+    {182302,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //HORDE_ROOST_WEST
+    {182303,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //HORDE_ROOST_NORTH
+    {182304,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048}, //HORDE_ROOST_EAST
+
+    {182305,530,-1825.4022,8039.2602,-26.08,-2.89725,0,0,0.992546,-0.121869}, //ALLY_BOMB_WAGON_SOUTH
+    {182306,530,-1515.37,8136.91,-20.42,-1.3439,0,0,0.622515,-0.782608}, //ALLY_BOMB_WAGON_WEST
+    {182307,530,-1377.95,7773.44,-10.31,-0.575959,0,0,0.284015,-0.95882}, //ALLY_BOMB_WAGON_NORTH
+    {182308,530,-1659.87,7733.15,-15.75,-2.80998,0,0,0.986286,-0.165048}, //ALLY_BOMB_WAGON_EAST
+
+    {182297,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //DESTROYED_HORDE_ROOST_SOUTH
+    {182298,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //DESTROYED_HORDE_ROOST_WEST
+    {182299,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //DESTROYED_HORDE_ROOST_NORTH
+    {182300,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048}  //DESTROYED_HORDE_ROOST_EAST
+};
+
+enum ControlNPCTypes{
+    NA_NPC_RESEARCHER = 0,
+    NA_NPC_QUARTERMASTER,
+    NA_NPC_BLADE_MERCHANT,
+    NA_NPC_FOOD_MERCHANT,
+    NA_NPC_AMMO,
+
+    NA_NPC_GUARD_01,
+    NA_NPC_GUARD_02,
+    NA_NPC_GUARD_03,
+    NA_NPC_GUARD_04,
+    NA_NPC_GUARD_05,
+    NA_NPC_GUARD_06,
+    NA_NPC_GUARD_07,
+    NA_NPC_GUARD_08,
+    NA_NPC_GUARD_09,
+    NA_NPC_GUARD_10,
+    NA_NPC_GUARD_11,
+    NA_NPC_GUARD_12,
+    NA_NPC_GUARD_13,
+    NA_NPC_GUARD_14,
+    NA_NPC_GUARD_15,
+
+    NA_CONTROL_NPC_NUM
+};
+
+const creature_type HordeControlNPCs[NA_CONTROL_NPC_NUM] = {
+    {18816,67,530,-1523.92,7951.76,-17.6942,3.51172},
+    {18821,67,530,-1527.75,7952.46,-17.6948,3.99317},
+    {21474,67,530,-1520.14,7927.11,-20.2527,3.39389},
+    {21484,67,530,-1524.84,7930.34,-20.182,3.6405},
+    {21483,67,530,-1570.01,7993.8,-22.4505,5.02655},
+    {18192,67,530,-1654.06,8000.46,-26.59,3.37},
+    {18192,67,530,-1487.18,7899.1,-19.53,0.954},
+    {18192,67,530,-1480.88,7908.79,-19.19,4.485},
+    {18192,67,530,-1540.56,7995.44,-20.45,0.947},
+    {18192,67,530,-1546.95,8000.85,-20.72,6.035},
+    {18192,67,530,-1595.31,7860.53,-21.51,3.747},
+    {18192,67,530,-1642.31,7995.59,-25.8,3.317},
+    {18192,67,530,-1545.46,7995.35,-20.63,1.094},
+    {18192,67,530,-1487.58,7907.99,-19.27,5.567},
+    {18192,67,530,-1651.54,7988.56,-26.5289,2.98451},
+    {18192,67,530,-1602.46,7866.43,-22.1177,4.74729},
+    {18192,67,530,-1591.22,7875.29,-22.3536,4.34587},
+    {18192,67,530,-1550.6,7944.45,-21.63,3.559},
+    {18192,67,530,-1545.57,7935.83,-21.13,3.448},
+    {18192,67,530,-1550.86,7937.56,-21.7,3.801}
+};
+
+const creature_type AllianceControlNPCs[NA_CONTROL_NPC_NUM] = {
+    {18817,469,530,-1591.18,8020.39,-22.2042,4.59022},
+    {18822,469,530,-1588.0,8019.0,-22.2042,4.06662},
+    {21485,469,530,-1521.93,7927.37,-20.2299,3.24631},
+    {21487,469,530,-1540.33,7971.95,-20.7186,3.07178},
+    {21488,469,530,-1570.01,7993.8,-22.4505,5.02655},
+    {18256,469,530,-1654.06,8000.46,-26.59,3.37},
+    {18256,469,530,-1487.18,7899.1,-19.53,0.954},
+    {18256,469,530,-1480.88,7908.79,-19.19,4.485},
+    {18256,469,530,-1540.56,7995.44,-20.45,0.947},
+    {18256,469,530,-1546.95,8000.85,-20.72,6.035},
+    {18256,469,530,-1595.31,7860.53,-21.51,3.747},
+    {18256,469,530,-1642.31,7995.59,-25.8,3.317},
+    {18256,469,530,-1545.46,7995.35,-20.63,1.094},
+    {18256,469,530,-1487.58,7907.99,-19.27,5.567},
+    {18256,469,530,-1651.54,7988.56,-26.5289,2.98451},
+    {18256,469,530,-1602.46,7866.43,-22.1177,4.74729},
+    {18256,469,530,-1591.22,7875.29,-22.3536,4.34587},
+    {18256,469,530,-1603.75,8000.36,-24.18,4.516},
+    {18256,469,530,-1585.73,7994.68,-23.29,4.439},
+    {18256,469,530,-1595.5,7991.27,-23.53,4.738}
+};
+
+enum WyvernStates{
+    WYVERN_NEU_HORDE = 1,
+    WYVERN_NEU_ALLIANCE = 2,
+    WYVERN_HORDE = 4,
+    WYVERN_ALLIANCE = 8
+};
+
+enum HalaaStates{
+    HALAA_N = 1,
+    HALAA_N_A = 2,
+    HALAA_A = 4,
+    HALAA_N_H = 8,
+    HALAA_H = 16
+};
+
+class Unit;
+class Creature;
+class OutdoorPvPNA;
+class OutdoorPvPObjectiveNA : public OutdoorPvPObjective
+{
+friend class OutdoorPvPNA;
+public:
+    OutdoorPvPObjectiveNA(OutdoorPvP * pvp);
+    bool Update(uint32 diff);
+    void FillInitialWorldStates(WorldPacket & data);
+    // used when player is activated/inactivated in the area
+    bool HandlePlayerEnter(Player * plr);
+    void HandlePlayerLeave(Player * plr);
+    bool HandleCustomSpell(Player *plr, uint32 spellId, GameObject * go);
+    int32 HandleOpenGo(Player *plr, uint64 guid);
+    uint32 GetAliveGuardsCount();
+protected:
+    // called when a faction takes control
+    void FactionTakeOver(uint32 team);
+
+    void DeSpawnNPCs();
+    void DeSpawnGOs();
+    void SpawnNPCsForTeam(uint32 team);
+    void SpawnGOsForTeam(uint32 team);
+
+    void UpdateWyvernRoostWorldState(uint32 roost);
+    void UpdateHalaaWorldState();
+
+    bool HandleCapturePointEvent(Player * plr, uint32 eventId);
+private:
+    bool m_capturable;
+    uint32 m_GuardsAlive;
+    uint32 m_ControllingFaction;
+    uint32 m_WyvernStateNorth;
+    uint32 m_WyvernStateSouth;
+    uint32 m_WyvernStateEast;
+    uint32 m_WyvernStateWest;
+    uint32 m_HalaaState;
+    uint32 m_RespawnTimer;
+    uint32 m_GuardCheckTimer;
+};
+
+class OutdoorPvPNA : public OutdoorPvP
+{
+friend class OutdoorPvPObjectiveNA;
+public:
+    OutdoorPvPNA();
+    bool SetupOutdoorPvP();
+    void HandlePlayerEnterZone(Player *plr, uint32 zone);
+    void HandlePlayerLeaveZone(Player *plr, uint32 zone);
+    bool Update(uint32 diff);
+    void FillInitialWorldStates(WorldPacket &data);
+    void SendRemoveWorldStates(Player * plr);
+    void HandleKillImpl(Player * plr, Unit * killed);
+    void BuffTeam(uint32 team);
+private:
+    OutdoorPvPObjectiveNA * m_obj;
+};
+
+#endif
Index: src/game/GameObject.h
===================================================================
--- src/game/GameObject.h	(revision 6743)
+++ src/game/GameObject.h	(working copy)
@@ -381,6 +381,7 @@
     uint32 animprogress;
     uint32 go_state;
     uint8 spawnMask;
+    uint32 ArtKit;
 };
 
 // GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
@@ -412,11 +413,17 @@
     public:
         explicit GameObject();
         ~GameObject();
+	
+		// Starts respawn time of GO - Custom (Tigu)
+		void StartRespawn()
+        {
+           m_respawnTime = time(NULL) + m_respawnDelayTime;
+        }
 
         void AddToWorld();
         void RemoveFromWorld();
 
-        bool Create(uint32 guidlow, uint32 name_id, Map *map, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, uint32 go_state);
+        bool Create(uint32 guidlow, uint32 name_id, Map *map, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, uint32 go_state, uint32 ArtKit = 0);
         void Update(uint32 p_time);
         static GameObject* GetGameObject(WorldObject& object, uint64 guid);
         GameObjectInfo const* GetGOInfo() const;
@@ -502,7 +509,7 @@
         uint32 GetGoState() const { return GetUInt32Value(GAMEOBJECT_STATE); }
         void SetGoState(uint32 state) { SetUInt32Value(GAMEOBJECT_STATE, state); }
         uint32 GetGoArtKit() const { return GetUInt32Value(GAMEOBJECT_ARTKIT); }
-        void SetGoArtKit(uint32 artkit) { SetUInt32Value(GAMEOBJECT_ARTKIT, artkit); }
+        void SetGoArtKit(uint32 artkit);
         uint32 GetGoAnimProgress() const { return GetUInt32Value(GAMEOBJECT_ANIMPROGRESS); }
         void SetGoAnimProgress(uint32 animprogress) { SetUInt32Value(GAMEOBJECT_ANIMPROGRESS, animprogress); }
 
Index: src/game/Chat.cpp
===================================================================
--- src/game/Chat.cpp	(revision 6743)
+++ src/game/Chat.cpp	(working copy)
@@ -107,6 +107,7 @@
         { "Mod32Value",     SEC_ADMINISTRATOR,  &ChatHandler::HandleMod32Value,                 "", NULL },
         { "anim",           SEC_GAMEMASTER,     &ChatHandler::HandleAnimCommand,                "", NULL },
         { "lootrecipient",  SEC_GAMEMASTER,     &ChatHandler::HandleGetLootRecipient,           "", NULL },
+        { "arena",          SEC_ADMINISTRATOR,  &ChatHandler::HandleDebugArenaCommand,          "", NULL },
         { NULL,             0,                  NULL,                                           "", NULL }
     };
 
@@ -456,6 +457,7 @@
         { "cometome",       SEC_ADMINISTRATOR,  &ChatHandler::HandleComeToMeCommand,            "", NULL },
         { "damage",         SEC_ADMINISTRATOR,  &ChatHandler::HandleDamageCommand,              "", NULL },
         { "combatstop",     SEC_GAMEMASTER,     &ChatHandler::HandleCombatStopCommand,          "", NULL },
+        { "flusharenapoints",    SEC_ADMINISTRATOR, &ChatHandler::HandleFlushArenaPointsCommand,         "",   NULL },
 
         { NULL,             0,                  NULL,                                           "", NULL }
     };
Index: src/game/OutdoorPvPMgr.cpp
===================================================================
--- src/game/OutdoorPvPMgr.cpp	(revision 0)
+++ src/game/OutdoorPvPMgr.cpp	(revision 0)
@@ -0,0 +1,219 @@
+#include "OutdoorPvPMgr.h"
+#include "OutdoorPvPHP.h"
+#include "OutdoorPvPNA.h"
+#include "OutdoorPvPTF.h"
+#include "OutdoorPvPZM.h"
+#include "OutdoorPvPSI.h"
+#include "OutdoorPvPEP.h"
+#include "Player.h"
+#include "Policies/SingletonImp.h"
+
+INSTANTIATE_SINGLETON_1( OutdoorPvPMgr );
+
+OutdoorPvPMgr::OutdoorPvPMgr()
+{
+    sLog.outDebug("Instantiating OutdoorPvPMgr");
+}
+
+OutdoorPvPMgr::~OutdoorPvPMgr()
+{
+    sLog.outDebug("Deleting OutdoorPvPMgr");
+    for(OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr)
+    {
+        (*itr)->DeleteSpawns();
+    }
+}
+
+void OutdoorPvPMgr::InitOutdoorPvP()
+{
+    // create new opvp
+    OutdoorPvP * pOP = new OutdoorPvPHP;
+    // respawn, init variables
+    if(!pOP->SetupOutdoorPvP())
+    {
+        sLog.outDebug("OutdoorPvP : HP init failed.");
+        delete pOP;
+    }
+    else
+    {
+        m_OutdoorPvPSet.insert(pOP);
+        sLog.outDebug("OutdoorPvP : HP successfully initiated.");
+    }
+
+
+    pOP = new OutdoorPvPNA;
+    // respawn, init variables
+    if(!pOP->SetupOutdoorPvP())
+    {
+        sLog.outDebug("OutdoorPvP : NA init failed.");
+        delete pOP;
+    }
+    else
+    {
+        m_OutdoorPvPSet.insert(pOP);
+        sLog.outDebug("OutdoorPvP : NA successfully initiated.");
+    }
+
+
+    pOP = new OutdoorPvPTF;
+    // respawn, init variables
+    if(!pOP->SetupOutdoorPvP())
+    {
+        sLog.outDebug("OutdoorPvP : TF init failed.");
+        delete pOP;
+    }
+    else
+    {
+        m_OutdoorPvPSet.insert(pOP);
+        sLog.outDebug("OutdoorPvP : TF successfully initiated.");
+    }
+
+    pOP = new OutdoorPvPZM;
+    // respawn, init variables
+    if(!pOP->SetupOutdoorPvP())
+    {
+        sLog.outDebug("OutdoorPvP : ZM init failed.");
+        delete pOP;
+    }
+    else
+    {
+        m_OutdoorPvPSet.insert(pOP);
+        sLog.outDebug("OutdoorPvP : ZM successfully initiated.");
+    }
+
+    pOP = new OutdoorPvPSI;
+    // respawn, init variables
+    if(!pOP->SetupOutdoorPvP())
+    {
+        sLog.outDebug("OutdoorPvP : SI init failed.");
+        delete pOP;
+    }
+    else
+    {
+        m_OutdoorPvPSet.insert(pOP);
+        sLog.outDebug("OutdoorPvP : SI successfully initiated.");
+    }
+
+    pOP = new OutdoorPvPEP;
+    // respawn, init variables
+    if(!pOP->SetupOutdoorPvP())
+    {
+        sLog.outDebug("OutdoorPvP : EP init failed.");
+        delete pOP;
+    }
+    else
+    {
+        m_OutdoorPvPSet.insert(pOP);
+        sLog.outDebug("OutdoorPvP : EP successfully initiated.");
+    }
+}
+
+void OutdoorPvPMgr::AddZone(uint32 zoneid, OutdoorPvP *handle)
+{
+    m_OutdoorPvPMap[zoneid] = handle;
+}
+
+
+void OutdoorPvPMgr::HandlePlayerEnterZone(Player *plr, uint32 zoneid)
+{
+    OutdoorPvPMap::iterator itr = m_OutdoorPvPMap.find(zoneid);
+    if(itr == m_OutdoorPvPMap.end())
+    {
+        // no handle for this zone, return
+        return;
+    }
+    // add possibly beneficial buffs to plr for zone
+    itr->second->HandlePlayerEnterZone(plr, zoneid);
+    plr->SendInitWorldStates();
+    sLog.outDebug("Player %u entered outdoorpvp id %u",plr->GetGUIDLow(), itr->second->GetTypeId());
+}
+
+void OutdoorPvPMgr::HandlePlayerLeaveZone(Player *plr, uint32 zoneid)
+{
+    OutdoorPvPMap::iterator itr = m_OutdoorPvPMap.find(zoneid);
+    if(itr == m_OutdoorPvPMap.end())
+    {
+        // no handle for this zone, return
+        return;
+    }
+    // inform the OutdoorPvP class of the leaving, it should remove the player from all objectives
+    itr->second->HandlePlayerLeaveZone(plr, zoneid);
+    sLog.outDebug("Player %u left outdoorpvp id %u",plr->GetGUIDLow(), itr->second->GetTypeId());
+}
+
+OutdoorPvP * OutdoorPvPMgr::GetOutdoorPvPToZoneId(uint32 zoneid)
+{
+    OutdoorPvPMap::iterator itr = m_OutdoorPvPMap.find(zoneid);
+    if(itr == m_OutdoorPvPMap.end())
+    {
+        // no handle for this zone, return
+        return NULL;
+    }
+    return itr->second;
+}
+
+void OutdoorPvPMgr::Update(uint32 diff)
+{
+    for(OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr)
+    {
+        (*itr)->Update(diff);
+    }
+}
+
+bool OutdoorPvPMgr::HandleCustomSpell(Player *plr, uint32 spellId, GameObject * go)
+{
+    for(OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr)
+    {
+        if((*itr)->HandleCustomSpell(plr,spellId,go))
+            return true;
+    }
+    return false;
+}
+
+bool OutdoorPvPMgr::HandleOpenGo(Player *plr, uint64 guid)
+{
+    for(OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr)
+    {
+        if((*itr)->HandleOpenGo(plr,guid))
+            return true;
+    }
+    return false;
+}
+
+bool OutdoorPvPMgr::HandleCaptureCreaturePlayerMoveInLos(Player * plr, Creature * c)
+{
+    for(OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr)
+    {
+        if((*itr)->HandleCaptureCreaturePlayerMoveInLos(plr,c))
+            return true;
+    }
+    return false;
+}
+
+void OutdoorPvPMgr::HandleGossipOption(Player *plr, uint64 guid, uint32 gossipid)
+{
+    for(OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr)
+    {
+        if((*itr)->HandleGossipOption(plr,guid,gossipid))
+            return;
+    }
+}
+
+bool OutdoorPvPMgr::CanTalkTo(Player * plr, Creature * c, GossipOption & gso)
+{
+    for(OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr)
+    {
+        if((*itr)->CanTalkTo(plr,c,gso))
+            return true;
+    }
+    return false;
+}
+
+void OutdoorPvPMgr::HandleDropFlag(Player *plr, uint32 spellId)
+{
+    for(OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr)
+    {
+        if((*itr)->HandleDropFlag(plr,spellId))
+            return;
+    }
+}
Index: src/game/Group.h
===================================================================
--- src/game/Group.h	(revision 6743)
+++ src/game/Group.h	(working copy)
@@ -232,6 +232,7 @@
             SendUpdate();
         }
         void SetBattlegroundGroup(BattleGround *bg) { m_bgGroup = bg; }
+        uint32 CanJoinBattleGroundQueue(uint32 bgTypeId, uint32 bgQueueType, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot);
 
         void ChangeMembersGroup(const uint64 &guid, const uint8 &group);
         void ChangeMembersGroup(Player *player, const uint8 &group);
Index: src/game/Unit.h
===================================================================
--- src/game/Unit.h	(revision 6743)
+++ src/game/Unit.h	(working copy)
@@ -511,6 +511,7 @@
     UNIT_NPC_FLAG_GUILD_BANKER          = 0x00800000,       // cause client to send 997 opcode
     UNIT_NPC_FLAG_UNK3                  = 0x01000000,       // cause client to send 1015 opcode
     UNIT_NPC_FLAG_GUARD                 = 0x10000000,       // custom flag for guards
+    UNIT_NPC_FLAG_OUTDOORPVP            = 0x20000000,       // custom flag for outdoor pvp creatures
 };
 
 enum MovementFlags
@@ -1003,6 +1004,7 @@
         void RemoveAurasWithDispelType( DispelType type );
 
         void RemoveAllAuras();
+        void RemoveArenaAuras(bool onleave = false);
         void RemoveAllAurasOnDeath();
         void DelayAura(uint32 spellId, uint32 effindex, int32 delaytime);
 
Index: src/game/Makefile.am
===================================================================
--- src/game/Makefile.am	(revision 6743)
+++ src/game/Makefile.am	(working copy)
@@ -177,6 +177,24 @@
 	ObjectPosSelector.h \
 	Opcodes.cpp \
 	Opcodes.h \
+	OutdoorPvP.cpp \
+	OutdoorPvP.h \
+	OutdoorPvPEP.cpp \
+	OutdoorPvPEP.h \
+	OutdoorPvPHP.cpp \
+	OutdoorPvPHP.h \
+	OutdoorPvPMgr.cpp \
+	OutdoorPvPMgr.h \
+	OutdoorPvPNA.cpp \
+	OutdoorPvPNA.h \
+	OutdoorPvPObjectiveAI.cpp \
+	OutdoorPvPObjectiveAI.h \
+	OutdoorPvPSI.cpp \
+	OutdoorPvPSI.h \
+	OutdoorPvPTF.cpp \
+	OutdoorPvPTF.h \
+	OutdoorPvPZM.cpp \
+	OutdoorPvPZM.h \
 	Path.h \
 	PetAI.cpp \
 	PetAI.h \
Index: src/game/BattleGround.cpp
===================================================================
--- src/game/BattleGround.cpp	(revision 6743)
+++ src/game/BattleGround.cpp	(working copy)
@@ -24,6 +24,7 @@
 #include "Language.h"
 #include "Chat.h"
 #include "SpellAuras.h"
+#include "ArenaTeam.h"
 #include "World.h"
 #include "Util.h"
 
@@ -47,6 +48,8 @@
     m_Name              = "";
     m_LevelMin          = 0;
     m_LevelMax          = 0;
+    m_InBGFreeSlotQueue = false;
+    m_SetDeleteThis     = false;
 
     m_MaxPlayersPerTeam = 0;
     m_MaxPlayers        = 0;
@@ -67,21 +70,54 @@
     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;
 
     m_PlayersCount[BG_TEAM_ALLIANCE]    = 0;
     m_PlayersCount[BG_TEAM_HORDE]       = 0;
+
+    m_PrematureCountDown = false;
+    m_PrematureCountDown = 0;
 }
 
 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 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());
+    // unload map
+    if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
+        if(map->IsBattleGroundOrArena())
+            ((BattleGroundMap*)map)->SetUnload();
+    // remove from bg free slot queue
+    this->RemoveFromBGFreeSlotQueue();
 }
 
 void BattleGround::Update(time_t diff)
 {
-
     if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
         //BG is empty
         return;
@@ -188,6 +224,33 @@
         m_ResurrectQueue.clear();
     }
 
+    // if less then minimum players are in on one side, then start premature finish timer
+    if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
+    {
+        if(!m_PrematureCountDown)
+        {
+            m_PrematureCountDown = true;
+            m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime();
+            SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
+        }
+        else if(m_PrematureCountDownTimer < diff)
+        {
+            // time's up!
+            EndBattleGround(0); // noone wins
+            m_PrematureCountDown = false;
+        } 
+        else 
+        {
+            uint32 newtime = m_PrematureCountDownTimer - diff;
+            // announce every minute
+            if(m_PrematureCountDownTimer != sBattleGroundMgr.GetPrematureFinishTime() && newtime / 60000 != m_PrematureCountDownTimer / 60000)
+                SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
+            m_PrematureCountDownTimer = newtime;
+        }
+    }
+    else if (m_PrematureCountDown)
+        m_PrematureCountDown = false;
+
     if(GetStatus() == STATUS_WAIT_LEAVE)
     {
         // remove all players from battleground after 2 minutes
@@ -239,7 +302,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);
     }
 }
@@ -265,7 +331,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);
@@ -285,7 +354,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);
     }
 }
@@ -302,7 +374,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);
     }
 }
@@ -324,7 +399,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);
     }
 }
@@ -345,30 +423,88 @@
 
 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
 
         SetWinner(WINNER_ALLIANCE);
     }
-    else
+    else if(winner == HORDE)
     {
-        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
 
         SetWinner(WINNER_HORDE);
     }
+    else
+    {
+        SetWinner(3);
+    }
 
     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 if(winner == HORDE)
+        {
+            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);
+            sLog.outDebug("--- %u ; %u ; %d ; %d ; %u ; %u ---",winner_rating,loser_rating,winner_chance,loser_chance,winner_change,loser_change);
+            if(winner == ALLIANCE)
+            {
+                SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);
+                SetArenaTeamRatingChangeForTeam(HORDE, loser_change);
+            }
+            else
+            {
+                SetArenaTeamRatingChangeForTeam(HORDE, winner_change);
+                SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);
+            }
+        }
+        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)
     {
         Player *plr = objmgr.GetPlayer(itr->first);
@@ -378,14 +514,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;
             RewardMark(plr,ITEM_WINNER_COUNT);
@@ -404,10 +556,28 @@
         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)
+    {
+        // update arena points only after increasing the player's match count!
+        winner_arena_team->UpdateArenaPointsHelper();
+        loser_arena_team->UpdateArenaPointsHelper();
+        // 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_UNIVERSAL, Source->GetGUID(), winmsg);
@@ -558,12 +728,16 @@
 
 void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
 {
+    uint32 team = GetPlayerTeam(guid);
+    bool participant = false;
     // 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);
+        // check if the player was a participant of the match, or only entered through gm command (goname)
+        participant = true;
     }
 
     std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
@@ -577,6 +751,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);
@@ -589,66 +767,106 @@
     {
         plr->ClearAfkReports();
 
-        if(isArena())
+        if(participant) // if the player was a match participant, remove auras, calc rating, update queue
         {
-            if(!sWorld.IsFFAPvPRealm())
-                plr->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
-        }
+            if(!team) team = plr->GetTeam();
 
-        WorldPacket data;
-        if(SendPacket)
-        {
-            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
-            plr->GetSession()->SendPacket(&data);
-        }
+            uint32 bgTypeId = GetTypeID();
+            uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
+            // if arena, remove the specific arena auras
+            if(isArena())
+            {
+                plr->RemoveArenaAuras(true);    // removes debuffs / dots etc., we don't want the player to die after porting out
+                bgTypeId=BATTLEGROUND_AA;       // set the bg type to all arenas (it will be used for queue refreshing)
 
-        // 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);
+                // summon old pet if there was one and there isn't a current pet
+                if(!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber())
+                {
+                    Pet* NewPet = new Pet;
+                    if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true))
+                        delete NewPet;
 
-        DecreaseInvitedCount(plr->GetTeam());
-        //we should update battleground queue, but only if bg isn't ending
-        if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)
-            sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].Update(GetTypeID(), GetQueueType());
+                    (plr)->SetTemporaryUnsummonedPetNumber(0);
+                }
 
-        if(!plr->GetBattleGroundId())
-            return;
+                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());
+                    }
+                }
+            }
 
-        Group * group = plr->GetGroup();
+            WorldPacket data;
+            if(SendPacket)
+            {
+                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0);
+                plr->GetSession()->SendPacket(&data);
+            }
 
-        // remove from raid group if exist
-        if(group && group == GetBgRaid(plr->GetTeam()))
-        {
-            if(!group->RemoveMember(guid, 0))               // group was disbanded
+            // 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(bgQueueTypeId);
+
+            DecreaseInvitedCount(team);
+            //we should update battleground queue, but only if bg isn't ending
+            if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)
+                sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueType());
+
+            Group * group = plr->GetGroup();
+            // remove from raid group if exist
+            if(group && group == GetBgRaid(team))
             {
-                SetBgRaid(plr->GetTeam(), NULL);
-                delete group;
+                if(!group->RemoveMember(guid, 0))               // group was disbanded
+                {
+                    SetBgRaid(team, NULL);
+                    delete group;
+                }
             }
+
+            // Let others know
+            sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
+            SendPacketToTeam(team, &data, plr, false);
         }
 
         // Do next only if found in battleground
         plr->SetBattleGroundId(0);                          // We're not in BG.
+        // reset destination bg team
+        plr->SetBGTeam(0);
 
-        // Let others know
-        sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
-        SendPacketToTeam(plr->GetTeam(), &data, plr, false);
-
         if(Transport)
         {
             plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO());
-            //sLog.outDetail("BATTLEGROUND: Sending %s to %f,%f,%f,%f", pl->GetName(), x,y,z,O);
         }
 
         // Log
         sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
     }
 
-    /// 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
@@ -660,6 +878,8 @@
     SetStartTime(0);
     SetEndTime(0);
     SetLastResurrectTime(0);
+    SetArenaType(0);
+    SetRated(false);
 
     m_Events = 0;
 
@@ -668,11 +888,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();
 }
 
@@ -688,9 +909,12 @@
 {
     // score struct must be created in inherited class
 
-    uint64 guid = plr->GetGUID();
     uint32 team = plr->GetBGTeam();
+    if(team==0)
+        team = plr->GetTeam();
 
+    uint64 guid = plr->GetGUID();
+
     BattleGroundPlayer bp;
     bp.LastOnlineTime = 0;
     bp.Team = team;
@@ -730,12 +954,15 @@
     else
     {
         if(GetStatus() == STATUS_WAIT_JOIN)                 // not started yet
-            plr->CastSpell(plr, SPELL_PREPARATION, true);   // reduces all mana cost of spells.
+        {
+            (plr)->SetTemporaryUnsummonedPetNumber(0);
+            plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
+
+            plr->SetHealth(plr->GetMaxHealth());
+            plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
+        }
     }
 
-    if(isArena())
-        plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
-
     // Log
     sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
 }
@@ -743,13 +970,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)
@@ -757,30 +991,66 @@
             sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
             return;
         }
-    }*/
+    }
 }
 
-/*
-this method should decide, if we can invite new player of certain team to BG, it is based on BATTLEGROUND_STATUS
-*/
-bool BattleGround::HasFreeSlotsForTeam(uint32 Team) const
+// get the number of free slots for team
+// works in similar way that HasFreeSlotsForTeam did, but this is needed for join as group
+uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
 {
     //if BG is starting ... invite anyone:
     if (GetStatus() == STATUS_WAIT_JOIN)
-        return GetInvitedCount(Team) < GetMaxPlayersPerTeam();
+        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;
+    uint32 otherIn;
     if (Team == ALLIANCE)
+    {
         otherTeam = GetInvitedCount(HORDE);
+        otherIn = GetPlayersCountByTeam(HORDE);
+    }
     else
+    {
         otherTeam = GetInvitedCount(ALLIANCE);
+        otherIn = GetPlayersCountByTeam(ALLIANCE);
+    }
     if (GetStatus() == STATUS_IN_PROGRESS)
-        return (GetInvitedCount(Team) <= otherTeam && GetInvitedCount(Team) < GetMaxPlayersPerTeam());
+    {
+        // difference based on ppl invited (not necessarily entered battle)
+        // default: allow 0
+        uint32 diff = 0;
+        // allow join one person if the sides are equal (to fill up bg to minplayersperteam)
+        if (otherTeam == GetInvitedCount(Team)) 
+            diff = 1;
+        // allow join more ppl if the other side has more players
+        else if(otherTeam > GetInvitedCount(Team))
+            diff = otherTeam - GetInvitedCount(Team);
 
-    return false;
+        // difference based on max players per team (don't allow inviting more)
+        uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
+
+        // difference based on players who already entered
+        // default: allow 0
+        uint32 diff3 = 0;
+        // allow join one person if the sides are equal (to fill up bg minplayersperteam)
+        if (otherIn == GetPlayersCountByTeam(Team))
+            diff3 = 1;
+        // allow join more ppl if the other side has more players
+        else if (otherIn > GetPlayersCountByTeam(Team))
+            diff3 = otherIn - GetPlayersCountByTeam(Team);
+
+        // return the minimum of the 3 differences
+
+        // min of diff and diff 2
+        diff = diff < diff2 ? diff : diff2;
+
+        // min of diff, diff2 and diff3
+        return diff < diff3 ? diff : diff3 ;
+    }
+
+    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
 {
     return GetPlayersSize() < GetMaxPlayers();
@@ -806,9 +1076,15 @@
             itr->second->HonorableKills += value;
             break;
         case SCORE_BONUS_HONOR:                             // Honor bonus
-            // reward honor instantly
-            if(Source->RewardHonor(NULL, 1, value))
-                itr->second->BonusHonor += value;
+            // do not add honor in arenas
+            if(isBattleGround())
+            {
+                // reward honor instantly
+                if(Source->RewardHonor(NULL, 1, value))
+                    itr->second->BonusHonor += value;
+            }
+            else
+
             break;
             //used only in EY, but in MSG_PVP_LOG_DATA opcode
         case SCORE_DAMAGE_DONE:                             // Damage Done
@@ -864,15 +1140,26 @@
 
 bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
 {
-    GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry);
-    if(!goinfo)
+    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
+    if(!map)
+        return false;
+
+    // must be created this way, adding to godatamap would add it to the base map of the instance
+    // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
+    // so we must create it specific for this instance
+    GameObject * go = new GameObject;
+    if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,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 = go->GetGUIDLow();
 
-    uint32 guid = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
-
+    // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
+    // iirc that was changed, so adding to go data map is no longer required if that was the only function using godata from GameObject without checking if it existed
     GameObjectData& data = objmgr.NewGOData(guid);
 
     data.id             = entry;
@@ -886,13 +1173,13 @@
     data.rotation2      = rotation2;
     data.rotation3      = rotation3;
     data.spawntimesecs  = respawnTime;
+    data.spawnMask      = 1;
     data.animprogress   = 100;
     data.go_state       = 1;
-    data.spawnMask      = 1;
-    objmgr.AddGameobjectToGrid(guid, &data);
-
-    m_BgObjects[type] = MAKE_NEW_GUID(guid, entry, HIGHGUID_GAMEOBJECT);
-
+*/
+    // add to world, so it can be later looked up from HashMapHolder
+    go->AddToWorld();
+    m_BgObjects[type] = go->GetGUID();
     return true;
 }
 
@@ -934,6 +1221,9 @@
 
 void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
 {
+    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
+    if(!map)
+        return;
     if( respawntime == 0 )
     {
         GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
@@ -942,30 +1232,27 @@
             //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
             if( obj->getLootState() == GO_JUST_DEACTIVATED )
                 obj->SetLootState(GO_READY);
-            obj->Respawn();
+            obj->SetRespawnTime(0);
+            map->Add(obj);
         }
-        else
-            objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, 0);
     }
     else
     {
         GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
         if(obj)
         {
+            map->Add(obj);
             obj->SetRespawnTime(respawntime);
             obj->SetLootState(GO_JUST_DEACTIVATED);
         }
-        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)
 {
-    // note: this should normally be FindMap
-    // but it's a hack to allow the battlegrounds to initialize at server startup
-    Map * map = MapManager::Instance().GetMap(GetMapId(), 0);
-    if(!map) return NULL;
+    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
+    if(!map)
+        return NULL;
 
     Creature* pCreature = new Creature;
     if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, entry, teamval))
@@ -989,9 +1276,39 @@
 
     map->Add(pCreature);
     m_BgCreatures[type] = pCreature->GetGUID();
+
     return  pCreature;
 }
+/*
+void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
+{
+    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
+    if(!map)
+        return false;
 
+    if(respawntime == 0)
+    {
+        Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
+        if(obj)
+        {
+            //obj->Respawn();                               // bugged
+            obj->SetRespawnTime(0);
+            objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
+            map->Add(obj);
+        }
+    }
+    else
+    {
+        Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
+        if(obj)
+        {
+            obj->setDeathState(DEAD);
+            obj->SetRespawnTime(respawntime);
+            map->Add(obj);
+        }
+    }
+}
+*/
 bool BattleGround::DelCreature(uint32 type)
 {
     Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
@@ -1072,8 +1389,11 @@
 
 void BattleGround::EndNow()
 {
+    RemoveFromBGFreeSlotQueue();
     SetStatus(STATUS_WAIT_LEAVE);
     SetEndTime(TIME_TO_AUTOREMOVE);
+    // inform invited players about the removal
+    sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
 }
 
 // Battleground messages are localized using the dbc lang, they are not client language dependent
@@ -1151,3 +1471,28 @@
     // to be able to remove insignia
     player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
 }
+
+// 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/ArenaTeam.cpp
===================================================================
--- src/game/ArenaTeam.cpp	(revision 6743)
+++ 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;
@@ -138,20 +138,43 @@
     {
         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);
-    }
 
     // hide promote/remove buttons
     if(CaptainGuid != PlayerGuid)
     {
         if(pl)
             pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
-        else
-            Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1, PlayerGuid);
     }
+
+    // setuint32valueindb is asynch, can't be used here
+    Tokens tokens;
+    if(!Player::LoadValuesArrayFromDB(tokens,PlayerGuid))
+        return false;
+
+    // arena team id
+    uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6);
+    char buf[11];
+    snprintf(buf,11,"%u",Id);
+    tokens[index] = buf;
+    // pers rating
+    index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5;
+    buf[11];
+    snprintf(buf,11,"%u",1500);
+    tokens[index] = buf;
+    // hide promote/remove buttons
+    if(CaptainGuid != PlayerGuid)
+    {
+        index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6);
+        buf[11];
+        snprintf(buf,11,"%u",1);
+        tokens[index] = buf;
+    }
+
+    Player::SaveValuesArrayInDB(tokens,PlayerGuid);
+
     return true;
 }
 
@@ -180,6 +203,22 @@
 
     delete result;
 
+    // only load here, so additional checks can be made
+    LoadStatsFromDB(ArenaTeamId);
+    LoadMembersFromDB(ArenaTeamId);
+
+    if(!GetMembersSize())
+    {
+        // arena team is empty, delete from db
+        CharacterDatabase.BeginTransaction();
+        CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
+        CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
+        CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId);
+        CharacterDatabase.CommitTransaction();
+        // return false
+        return false;
+    }
+
     return true;
 }
 
@@ -207,7 +246,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;
 
@@ -216,6 +255,14 @@
         fields = result->Fetch();
         ArenaTeamMember newmember;
         newmember.guid          = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
+        // check if this member is in this arenateam
+        // based on character data field
+        if(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6),newmember.guid) != ArenaTeamId)
+        {
+            // the player's registered arena team for this slot isn't this team, so delete member info from here
+            CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u' AND arenateamid = '%u'",fields[0].GetUInt32(), ArenaTeamId);
+            continue;
+        }
         LoadPlayerStats(&newmember);
         newmember.played_week   = fields[1].GetUInt32();
         newmember.wons_week     = fields[2].GetUInt32();
@@ -276,17 +323,36 @@
     }
 
     Player *player = objmgr.GetPlayer(guid);
+    // this will be ugly. because of the asynchronous sql handling, we have to set all the fields of the player at once, and save them at once, or else the save will only modify the last field.
+    // rip off of setuint32valueindb
     if(player)
     {
         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);
+        }
     }
-    else
+
+    // we have to do it this way, setuint32valueindb is asynch, unsafe to use multiple times in a row on the same player
+    Tokens tokens;
+    if(!Player::LoadValuesArrayFromDB(tokens,guid))
+        return;
+
+    for(int i = 0; i < 6; ++i)
     {
-        Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), 0, guid);
+        uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i;
+        char buf[11];
+        snprintf(buf,11,"%u",0);
+        tokens[index] = buf;
     }
 
-    CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u'", GUID_LOPART(guid));
+    Player::SaveValuesArrayInDB(tokens,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)
@@ -313,6 +379,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);
@@ -342,7 +409,7 @@
             data << uint32(itr->wons_week);                 // wins this week
             data << uint32(itr->played_season);             // played this season
             data << uint32(itr->wons_season);               // wins this season
-            data << uint32(0);                              // personal rating?
+            data << uint32(pl->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5));                              // personal rating?
         }
         else
         {
@@ -356,7 +423,7 @@
             data << uint32(itr->wons_week);                 // wins this week
             data << uint32(itr->played_season);             // played this season
             data << uint32(itr->wons_season);               // wins this season
-            data << uint32(0);                              // personal rating?
+            data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, itr->guid));                              // personal rating?
         }
     }
     session->SendPacket(&data);
@@ -391,6 +458,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_TEAMS, 8+1+4*6);
@@ -398,10 +477,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);                                      // 2.3.3 personal rating?
+    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(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, guid));                                       // unk, 2.3.3 (personal rating?)
+
     session->SendPacket(&data);
 }
 
@@ -494,24 +583,211 @@
     return false;
 }
 
+uint32 ArenaTeam::GetPoints(uint32 MemberRating)
+{
+    // returns how many points would be awarded with this team type with this rating
+    float points;
+
+    uint32 rating = MemberRating + 150 < stats.rating ? MemberRating : stats.rating;
+
+    if(rating<=1500)
+    {
+        points = (float)rating * 0.22f + 14.0f;
+    }
+    else
+    {
+        points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)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)floor(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)ceil(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)ceil(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)floor(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;
+        }
+    }
+}
+
+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 = ceil(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)
+        {
+            // do it separately for online and offline players
+            // online players might have modified personal rating in MemberLost/MemberWon, that's not already saved to DB because of asynch queries
+            // offline player cant have a personal rating not matching the db
+            Player * plr = objmgr.GetPlayer(itr->guid);
+            uint32 points_to_add = 0;
+            if(plr)
+                points_to_add = GetPoints(plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5));
+            else
+                points_to_add = GetPoints(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5,itr->guid));
+            // it's enough to set the points in memory, the saving is done in separate function
+            CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, Id, itr->guid);
+        }
+        // the player failed to participate in enough games, so no points for him
+        else
+        {
+            CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", 0, Id, itr->guid);
+        }
+    }
+}
+
+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' WHERE arenateamid = '%u' AND guid = '%u'", itr->played_week, itr->wons_week, itr->played_season, itr->wons_season, Id, itr->guid);
+    }
+}
+
+void ArenaTeam::FinishWeek()
+{
+    stats.games = 0; // played this week
+    stats.wins = 0; // wins this week
+    for(MemberList::iterator itr = members.begin(); itr !=  members.end(); ++itr)
+    {
+        itr->played_week = 0;
+        itr->wons_week = 0;
+    }
+}
+
 /*
 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/OutdoorPvPEP.h
===================================================================
--- src/game/OutdoorPvPEP.h	(revision 0)
+++ src/game/OutdoorPvPEP.h	(revision 0)
@@ -0,0 +1,272 @@
+#ifndef OUTDOOR_PVP_EP_
+#define OUTDOOR_PVP_EP_
+
+#include "OutdoorPvP.h"
+
+#include "Database/DBCStructure.h"
+
+const uint32 EP_AllianceBuffs[4] = {11413, 11414, 11415, 1386};
+
+const uint32 EP_HordeBuffs[4] = {30880, 30683, 30682, 29520};
+
+const uint32 EP_GraveYardZone = 139;
+
+const uint32 EP_GraveYardId = 927;
+
+const uint32 EPBuffZonesNum = 3;
+
+const uint32 EP_EWT_CM = 17690;
+const uint32 EP_CGT_CM = 17689;
+const uint32 EP_NPT_CM = 17696;
+const uint32 EP_PWT_CM = 17698;
+
+const uint32 EPBuffZones[EPBuffZonesNum] = {139, 2017, 2057};
+
+enum EP_TaxiNodes {
+    EP_CGT_Taxi = 87,
+    EP_EWT_Taxi = 86,
+    EP_NPT_Taxi = 85,
+    EP_PWT_Taxi = 84
+};
+
+enum EP_EastwallTowerWorldStates {
+    EP_EWT_A = 2354,
+    EP_EWT_H = 2356,
+    EP_EWT_A_P = 2357, // ally progressing
+    EP_EWT_H_P = 2358,
+    EP_EWT_N_A = 2359, // ally conquested
+    EP_EWT_N_H = 2360,
+    EP_EWT_N = 2361
+};
+
+enum EP_NorthpassTowerWorldStates {
+    EP_NPT_N = 2352,
+    EP_NPT_N_A = 2362,
+    EP_NPT_N_H = 2363,
+    EP_NPT_A_P = 2364,
+    EP_NPT_H_P = 2365,
+    EP_NPT_A = 2372,
+    EP_NPT_H = 2373
+};
+
+enum EP_PlagewoodTowerWorldStates {
+    EP_PWT_N_A = 2366,
+    EP_PWT_N_H = 2353, //2367 not present! use neutral!
+    EP_PWT_A_P = 2368,
+    EP_PWT_H_P = 2369,
+    EP_PWT_A = 2370,
+    EP_PWT_H = 2371,
+    EP_PWT_N = 2353
+};
+
+enum EP_CrownGuardTowerWorldStates {
+    EP_CGT_N_A = 2374,
+    EP_CGT_N_H = 2375,
+    EP_CGT_A_P = 2376,
+    EP_CGT_H_P = 2377,
+    EP_CGT_A = 2378,
+    EP_CGT_H = 2379,
+    EP_CGT_N = 2355
+};
+
+enum EP_WorldStates {
+    EP_UI_TOWER_SLIDER_DISPLAY = 2426,
+    EP_UI_TOWER_SLIDER_POS = 2427,
+    EP_UI_TOWER_SLIDER_N = 2428,
+
+    EP_UI_TOWER_COUNT_A = 2327,
+    EP_UI_TOWER_COUNT_H = 2328
+};
+
+enum EP_Summons {
+    EP_EWT_COMMANDER = 0,
+    EP_EWT_SOLDIER1,
+    EP_EWT_SOLDIER2,
+    EP_EWT_SOLDIER3,
+    EP_EWT_SOLDIER4,
+    EP_PWT_FLIGHTMASTER,
+};
+
+enum EP_GoSummons {
+    EP_NPT_BUFF = 0,
+    EP_NPT_FLAGS,
+    EP_EWT_FLAGS,
+    EP_CGT_FLAGS,
+    EP_PWT_FLAGS
+};
+
+enum EP_Towers {
+    EP_EWT = 0, // plaguelands 03
+    EP_NPT,// plaguelands 01
+    EP_PWT,// plaguelands 04
+    EP_CGT,// plaguelands 02
+    EP_TOWER_NUM
+};
+
+const go_type EPCapturePoints[EP_TOWER_NUM] = {
+    {182097,0,2574.51,-4794.89,144.704,-1.45003,-0.097056,0.095578,-0.656229,0.742165},
+    {181899,0,3181.08,-4379.36,174.123,-2.03472,-0.065392,0.119494,-0.842275,0.521553},
+    {182098,0,2962.71,-3042.31,154.789,2.08426,-0.074807,-0.113837,0.855928,0.49883},
+    {182096,0,1860.85,-3731.23,196.716,-2.53214,0.033967,-0.131914,0.944741,-0.298177}
+};
+
+const go_type EPTowerFlags[EP_TOWER_NUM] = {
+    {182106,0,2569.60,-4772.93,115.399,2.72271,0,0,0.978148,0.207912},
+    {182106,0,3148.17,-4365.51,145.029,1.53589,0,0,0.694658,0.71934},
+    {182106,0,2992.63,-3022.95,125.593,3.03687,0,0,0.99863,0.052336},
+    {182106,0,1838.42,-3703.56,167.713,0.890118,0,0,0.430511,0.902585}
+};
+
+const uint32 EPTowerPlayerEnterEvents[EP_TOWER_NUM] = {10691,10699,10701,10705};
+
+const uint32 EPTowerPlayerLeaveEvents[EP_TOWER_NUM] = {10692,10698,10700,10704};
+
+const uint32 EP_NUM_CREATURES = 6;
+const uint32 EP_EWT_NUM_CREATURES = 5;
+
+// one lordaeron commander, 4 soldiers
+// should be spawned at EWT and follow a path, but trans-grid pathing isn't safe, so summon them directly at NPT
+const creature_type EP_EWT_Summons_A[EP_EWT_NUM_CREATURES] = {
+    {17635,469,0, 3167.61,-4352.09,138.20,4.5811},
+    {17647,469,0, 3172.74,-4352.99,139.14,4.9873},
+    {17647,469,0, 3165.89,-4354.46,138.67,3.7244},
+    {17647,469,0, 3164.65,-4350.26,138.22,2.4794},
+    {17647,469,0, 3169.91,-4349.68,138.37,0.7444}
+};
+
+const creature_type EP_EWT_Summons_H[EP_EWT_NUM_CREATURES] = {
+    {17995,67,0, 3167.61,-4352.09,138.20,4.5811},
+    {17996,67,0, 3172.74,-4352.99,139.14,4.9873},
+    {17996,67,0, 3165.89,-4354.46,138.67,3.7244},
+    {17996,67,0, 3164.65,-4350.26,138.22,2.4794},
+    {17996,67,0, 3169.91,-4349.68,138.37,0.7444}
+};
+
+enum EP_TowerStates {
+    EP_TS_N = 1,
+    EP_TS_N_A = 2,
+    EP_TS_N_H = 4,
+    EP_TS_A_P = 8,
+    EP_TS_H_P = 16,
+    EP_TS_A = 32,
+    EP_TS_H = 64
+};
+
+// when spawning, pay attention at setting the faction manually!
+const creature_type EP_PWT_FlightMaster = {17209,0,0,2987.5,-3049.11,120.126,5.75959};
+
+// after spawning, modify the faction so that only the controller will be able to use it with SetUInt32Value(GAMEOBJECT_FACTION, faction_id);
+const go_type EP_NPT_LordaeronShrine = {181682,0,3167.72,-4355.91,138.785,1.69297,0,0,0.748956,0.66262};
+
+class OutdoorPvPEP;
+
+class OutdoorPvPObjectiveEP_EWT : public OutdoorPvPObjective
+{
+friend class OutdoorPvPEP;
+public:
+    OutdoorPvPObjectiveEP_EWT(OutdoorPvP * pvp);
+    bool Update(uint32 diff);
+    void FillInitialWorldStates(WorldPacket & data);
+    // used when player is activated/inactivated in the area
+    bool HandlePlayerEnter(Player * plr);
+    void HandlePlayerLeave(Player * plr);
+protected:
+    bool HandleCapturePointEvent(Player * plr, uint32 eventId);
+    void SummonSupportUnitAtNorthpassTower(uint32 team);
+    void UpdateTowerState();
+protected:
+    uint32 m_TowerState;
+};
+
+class OutdoorPvPObjectiveEP_NPT : public OutdoorPvPObjective
+{
+friend class OutdoorPvPEP;
+public:
+    OutdoorPvPObjectiveEP_NPT(OutdoorPvP * pvp);
+    bool Update(uint32 diff);
+    void FillInitialWorldStates(WorldPacket & data);
+    // used when player is activated/inactivated in the area
+    bool HandlePlayerEnter(Player * plr);
+    void HandlePlayerLeave(Player * plr);
+protected:
+    bool HandleCapturePointEvent(Player * plr, uint32 eventId);
+    void SummonGO(uint32 team);
+    void UpdateTowerState();
+protected:
+    uint32 m_TowerState;
+};
+
+class OutdoorPvPObjectiveEP_CGT : public OutdoorPvPObjective
+{
+friend class OutdoorPvPEP;
+public:
+    OutdoorPvPObjectiveEP_CGT(OutdoorPvP * pvp);
+    bool Update(uint32 diff);
+    void FillInitialWorldStates(WorldPacket & data);
+    // used when player is activated/inactivated in the area
+    bool HandlePlayerEnter(Player * plr);
+    void HandlePlayerLeave(Player * plr);
+protected:
+    bool HandleCapturePointEvent(Player * plr, uint32 eventId);
+    void LinkGraveYard(uint32 team);
+    void UpdateTowerState();
+protected:
+    uint32 m_TowerState;
+};
+
+class OutdoorPvPObjectiveEP_PWT : public OutdoorPvPObjective
+{
+friend class OutdoorPvPEP;
+public:
+    OutdoorPvPObjectiveEP_PWT(OutdoorPvP * pvp);
+    bool Update(uint32 diff);
+    void FillInitialWorldStates(WorldPacket & data);
+    // used when player is activated/inactivated in the area
+    bool HandlePlayerEnter(Player * plr);
+    void HandlePlayerLeave(Player * plr);
+    bool HandleGossipOption(Player *plr, uint64 guid, uint32 gossipid);
+protected:
+    bool HandleCapturePointEvent(Player * plr, uint32 eventId);
+    void SummonFlightMaster(uint32 team);
+    void UpdateTowerState();
+    // copy from player.h
+    bool SetTaximaskNode(uint32 nodeidx)
+    {
+        uint8  field   = uint8((nodeidx - 1) / 32);
+        uint32 submask = 1<<((nodeidx-1)%32);
+        if ((m_taximask[field] & submask) != submask )
+        {
+            m_taximask[field] |= submask;
+            return true;
+        }
+        else
+            return false;
+    }
+protected:
+    uint32 m_TowerState;
+    TaxiMask m_taximask;
+};
+
+class OutdoorPvPEP : public OutdoorPvP
+{
+friend class OutdoorPvPObjectiveEP_EWT;
+friend class OutdoorPvPObjectiveEP_NPT;
+friend class OutdoorPvPObjectiveEP_PWT;
+friend class OutdoorPvPObjectiveEP_CGT;
+public:
+    OutdoorPvPEP();
+    bool SetupOutdoorPvP();
+    void HandlePlayerEnterZone(Player *plr, uint32 zone);
+    void HandlePlayerLeaveZone(Player *plr, uint32 zone);
+    bool Update(uint32 diff);
+    void FillInitialWorldStates(WorldPacket &data);
+    void SendRemoveWorldStates(Player * plr);
+    void BuffTeams();
+private:
+    // how many towers are controlled
+    uint32 EP_Controls[EP_TOWER_NUM];
+    uint32 m_AllianceTowersControlled;
+    uint32 m_HordeTowersControlled;
+};
+
+#endif
Index: src/game/World.cpp
===================================================================
--- src/game/World.cpp	(revision 6743)
+++ src/game/World.cpp	(working copy)
@@ -53,7 +53,9 @@
 #include "WorldSocket.h"
 #include "GridNotifiersImpl.h"
 #include "CellImpl.h"
+#include "ObjectAccessor.h"			// custom (Tigu)
 #include "InstanceSaveMgr.h"
+#include "OutdoorPvPMgr.h"
 #include "WaypointManager.h"
 #include "Util.h"
 
@@ -69,6 +71,16 @@
 float World::m_VisibleUnitGreyDistance        = 0;
 float World::m_VisibleObjectGreyDistance      = 0;
 
+// GO spawn - Custom (Tigu)
+bool  World::m_forceNoRespawn                 = false;
+bool  World::m_forceRespawn                   = false;
+int   World::m_forceTimeSec					  = 0;
+
+int gostime[10];
+int gosguid[10];
+GameObject *go1[10];
+// - end -
+
 // ServerMessages.dbc
 enum ServerMessageType
 {
@@ -719,6 +731,13 @@
     m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvP", true);
     m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvE", true);
 
+    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_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault("Arena.AutoDistributeInterval", 7);
+
+    m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault("BattleGround.PrematureFinishTimer", 0);
+
     m_configs[CONFIG_THREAT_RADIUS] = sConfig.GetIntDefault("ThreatRadius", 100);
 
     // always use declined names in the russian client
@@ -1095,6 +1114,7 @@
     m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000);
                                                             //Update "uptime" table based on configuration entry in minutes.
     m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*1000);  //erase corpses every 20 minutes
+	m_timer1.SetInterval(5);								// custom (Tigu)
 
     //to set mailtimer to return mails every day between 4 and 5 am
     //mailtimer is increased when updating auctions
@@ -1116,7 +1136,11 @@
     ///- Initialize Battlegrounds
     sLog.outString( "Starting BattleGround System" );
     sBattleGroundMgr.CreateInitialBattleGrounds();
+    sBattleGroundMgr.InitAutomaticArenaPointDistribution();
 
+    sLog.outString( "Starting Outdoor PvP System" );
+    sOutdoorPvPMgr.InitOutdoorPvP();
+
     //Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager
     sLog.outString( "Loading Transports..." );
     MapManager::Instance().LoadTransports();
@@ -1185,6 +1209,11 @@
             m_timers[i].Update(diff);
     else m_timers[i].SetCurrent(0);
 
+	// GO Spawn - Custom(Tigu)
+	if(m_timer1.GetCurrent()>=0)
+       m_timer1.Update(diff);
+    else m_timer1.SetCurrent(0); // - end -
+
     ///- Update the game time and check for shutdown time
     _UpdateGameTime();
 
@@ -1266,6 +1295,14 @@
         UpdateSessions(diff);
     }
 
+    // GO Spawn - Custom(Tigu)
+	if (m_timer1.Passed())
+    {
+        m_timer1.Reset();
+
+        RefreshGOSpawns(diff);
+    } // - end -
+
     /// <li> Handle weather updates when the timer has passed
     if (m_timers[WUPDATE_WEATHERS].Passed())
     {
@@ -1309,6 +1346,8 @@
             ScriptsProcess();
 
         sBattleGroundMgr.Update(diff);
+
+        sOutdoorPvPMgr.Update(diff);
     }
 
     // execute callbacks from sql queries that were queued recently
@@ -1709,13 +1748,47 @@
                 }
 
                 if( go->isSpawned() )
+				{
+                    // "despawn - custom (Tigu)"
+                    // ---------------------------------
+                    m_forceRespawn = true;
+                    m_forceTimeSec = step.script->datalong2;
+                    go->SetLootState(GO_ACTIVATED);
+                    //WorldDatabase.PQuery("INSERT IGNORE INTO gameobject_respawn VALUES ('%u', UNIX_TIMESTAMP()+%u, '0')", step.script->datalong, step.script->datalong2 );
+                    // ---------------------------------
                     break;                                  //gameobject already spawned
+	  		    } 
+                    else
+                { // - end -
 
                 go->SetLootState(GO_READY);
                 go->SetRespawnTime(time_to_despawn);        //despawn object in ? seconds
+				// -------------------------------------------------------- custom (Tigu)
+                //WorldDatabase.PQuery("INSERT IGNORE INTO gameobject_respawn VALUES ('%u', '2147483647', '0')", step.script->datalong);
 
-                MapManager::Instance().GetMap(go->GetMapId(), go)->Add(go);
+                //MapManager::Instance().GetMap(go->GetMapId(), go)->Add(go);
+
+                go->Respawn();
+
+                int i=0;
+                bool proceeded1=false;
+
+                do { 
+                    if(go1[i]!=NULL)i++; else 
+                    {
+                    gosguid[i]=step.script->datalong;
+                    gostime[i]=step.script->datalong2*1000;
+                    go1[i]=go;
+
+                    proceeded1=true;
+                    }
+                }while(i<10 && proceeded1==false);
+                // --------------------------------------------------------
+                WorldDatabase.PQuery("INSERT IGNORE INTO gameobject_respawn VALUES ('%u', '2147483647', '0')", step.script->datalong);
+				// - end -
+
                 break;
+				}
             }
             case SCRIPT_COMMAND_OPEN_DOOR:
             {
@@ -2497,3 +2570,24 @@
     m_maxActiveSessionCount = std::max(m_maxActiveSessionCount,uint32(m_sessions.size()-m_QueuedPlayer.size()));
     m_maxQueuedSessionCount = std::max(m_maxQueuedSessionCount,uint32(m_QueuedPlayer.size()));
 }
+
+// Refresh GO - custom (Tigu)
+void World::RefreshGOSpawns(time_t diff)
+{
+    for(int i=0;i<10;i++) // loop all
+    {
+        if (go1[i]!=NULL) // check if empty
+        { 
+            if (gostime[i] <= diff)
+                {
+                    // "despawn"
+                    m_forceNoRespawn = true;
+                    go1[i]->SetLootState(GO_ACTIVATED);
+                    gostime[i]=0;
+                    go1[i]=NULL;
+                    gosguid[i]=0;
+                } else
+            gostime[i] = gostime[i]- diff;
+        }
+    }
+}
Index: src/game/BattleGroundHandler.cpp
===================================================================
--- src/game/BattleGroundHandler.cpp	(revision 6743)
+++ 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"
 #include "Language.h"
 
 void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data )
@@ -76,17 +79,24 @@
     uint32 bgTypeId;
     uint32 instanceId;
     uint8 joinAsGroup;
+    Group * grp;
 
     recv_data >> guid;                                      // battlemaster guid
     recv_data >> bgTypeId;                                  // battleground type id (DBC id)
     recv_data >> instanceId;                                // instance id, 0 if First Available selected
     recv_data >> joinAsGroup;                               // join as group
 
-    sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT " for BG (Type: %u)", guid, bgTypeId);
-
-    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)                  // cheating?
+    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+    {
+        sLog.outError("Battleground: 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;
@@ -98,74 +108,150 @@
     if(!unit->isBattleMaster())                             // it's not battlemaster
         return;
 
-    // check Deserter debuff
-    if( !_player->CanJoinToBattleground() )
+    // 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)))
     {
-        WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
-        data << (uint32) 0xFFFFFFFE;
-        _player->GetSession()->SendPacket(&data);
+        sLog.outError("Battleground: no available bg / template found");
         return;
     }
 
-    // check existence
-    BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
-    if(!bg)
-        return;
-
-    if(joinAsGroup && _player->GetGroup())
+    // check queueing conditions
+    if(!joinAsGroup)
     {
-        Group *grp = _player->GetGroup();
-        for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
+        // check Deserter debuff
+        if( !_player->CanJoinToBattleground() )
         {
-            Player *member = itr->getSource();
-            if(!member) continue;
-
-            if( !member->CanJoinToBattleground() )
+            WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
+            data << (uint32) 0xFFFFFFFE;
+            _player->GetSession()->SendPacket(&data);
+            return;
+        }
+        // check if already in queue
+        if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
+            //player is already in this queue
+            return;
+        // check if has free queue slots
+        if(!_player->HasFreeBattleGroundQueueId())
+            return;
+    }
+    else
+    {
+        grp = _player->GetGroup();
+        // no group found, error
+        if(!grp)
+            return;
+        uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
+        switch(err)
+        {
+            // TODO: add error-based feedback to players in all cases
+        case BG_JOIN_ERR_GROUP_TOO_MANY:
             {
-                WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
-                data << (uint32) 0xFFFFFFFE;
-                _player->GetSession()->SendPacket(&data);
-                continue;
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_TOO_LARGE), NULL);
+            SendPacket(&data);
             }
-            if (member->InBattleGroundQueueForBattleGroundType(bgTypeId))
-                //player is already in this queue
-                continue;
-
+            return;
+            break;
+        case BG_JOIN_ERR_OFFLINE_MEMBER:
+            {
             WorldPacket data;
-                                                            // add to queue
-            uint32 queueSlot = member->AddBattleGroundQueueId(bgTypeId);
-            if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_OFFLINE_MEMBER), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_MIXED_FACTION:
             {
-                // fill data packet
-                //member->GetSession()->SendPacket(data);
-                continue;
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_FACTION), NULL);
+            SendPacket(&data);
             }
+            return;
+            break;
+        case BG_JOIN_ERR_MIXED_LEVELS:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_LEVELS), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_GROUP_DESERTER:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_DESERTER), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_ALL_QUEUES_USED:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+            // all ok, can join
+        case BG_JOIN_ERR_OK:
+            break;
+            // these aren't possible outcomes in bgs 
+        case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
+        case BG_JOIN_ERR_MIXED_ARENATEAM:
+            return;
+            break;
+            // not the above? shouldn't happen, don't let join
+        default:
+            return;
+            break;
+        };
+    }
 
+    // if we're here, then the conditions to join a bg are met. We can proceed in joining.
+
+    // _player->GetGroup() was already checked, grp is already initialized
+    if(joinAsGroup /* && _player->GetGroup()*/)
+    {
+        sLog.outDebug("Battleground: the following players are joining as group:");
+        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;   // this should never happen
+
+            uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);           // add to queue
+
             // store entry point coords (same as leader entry point)
             member->SetBattleGroundEntryPoint(_player->GetMapId(),_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);
             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);
+            sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
         }
+        sLog.outDebug("Battleground: group end");
+        sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
     }
     else
     {
-        if (_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
-            //player is already in this queue
-            return;
-        uint32 queueSlot = _player->AddBattleGroundQueueId(bgTypeId);
-        if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
-        {
-            WorldPacket data;
-            // fill data packet
-            //SendPacket(data);
-            return;
-        }
-
+        // already checked if queueSlot is valid, now just get it
+        uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
         // store entry point coords
         _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
 
@@ -173,7 +259,11 @@
                                                             // 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());
+        sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
     }
 }
 
@@ -247,13 +337,12 @@
     uint32 bgTypeId;
     recv_data >> bgTypeId;                                  // id from DBC
 
-    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)                  // cheating?
+    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+    {
+        sLog.outError("Battleground: invalid bgtype received.");
         return;
+    }
 
-    // can't be received if player not in BG queue
-    if(!_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
-        return;
-
     BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
 
     if(!bl)
@@ -270,80 +359,186 @@
 
     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;
 
-    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)                  // cheating?
-        return;
+    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;
 
-    if(!_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
+                // 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;
+    }
 
-    BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
-    if(!bg)
+    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;
 
-    uint32 queueSlot = 0;
-    WorldPacket data;
-    switch(action)
+    // if action == 1, then instanceId is _required_
+    if(!instanceId && action == 1)
     {
-        case 1:                                             // port to battleground
-            // cheating?
-            if(!_player->IsInvitedForBattleGroundType(bgTypeId))
-                return;
+        sLog.outError("Battleground: instance not found.");
+        return;
+    }
 
-            // check if player is not deserter
-            if( !_player->CanJoinToBattleground() )
-            {
-                WorldPacket data2;
-                data2.Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
-                data2 << (uint32) 0xFFFFFFFE;
-                SendPacket(&data2);
-                return;
-            }
+    BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);
 
-            // if the player is dead, resurrect him before teleport
-            if(!_player->isAlive())
-            {
-                _player->ResurrectPlayer(1.0f,false);
-                _player->SpawnCorpseBones();
-            }
+    // 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);
 
-            // leave current group
-            _player->RemoveFromGroup();
+    if(!bg)
+    {
+        sLog.outError("Battleground: bg not found.");
+        return;
+    }
 
-            // packet to player about BG status
-            queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);
-            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
-            _player->GetSession()->SendPacket(&data);
+    bgTypeId = bg->GetTypeID();
 
-            // remove battleground queue status from BGmgr
-            sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), false);
+    if(_player->InBattleGroundQueue())
+    {
+        uint32 queueSlot = 0;
+        uint32 team = 0;
+        uint32 arenatype = 0;
+        uint32 israted = 0;
+        uint32 rating = 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;
+            rating = pitr->second.GroupInfo->ArenaTeamRating;
+        }
+        else
+        {
+            sLog.outError("Battleground: Invalid player queue info!");
+            return;
+        }
+        WorldPacket data;
+        switch(action)
+        {
+            case 1:                                     // port to battleground
+                if(!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
+                    return;                                     // cheating?
+                // resurrect the player
+                if(!_player->isAlive())
+                {
+                    _player->ResurrectPlayer(1.0f,false);
+                    _player->SpawnCorpseBones();
+                }
+                // stop taxi flight at port
+                if(_player->isInFlight())
+                {
+                    _player->GetMotionMaster()->MovementExpired();
+                    _player->m_taxi.ClearTaxiDestinations();
+                }
+                _player->RemoveFromGroup();
+                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[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
+                // this is still needed here if battleground "jumping" shouldn't add deserter debuff
+                // also this required to prevent stuck at old battleground after SetBattleGroundId set to new
+                if( BattleGround *currentBg = _player->GetBattleGround() )
+                    currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
 
-            // this is still needed here if battleground "jumping" shouldn't add deserter debuff
-            // also this required to prevent stuck at old battleground after SetBattleGroundId set to new
-            if (BattleGround *currentBg = _player->GetBattleGround())
-                currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
-
-            _player->SetBattleGroundId(bg->GetTypeID());
-            sBattleGroundMgr.SendToBattleGround(_player, bgTypeId);
-            bg->AddPlayer(_player);
-            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
-            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
-            sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), true);
-            SendPacket(&data);
-            break;
-        default:
-            sLog.outError("Battleground port: unknown action %u", action);
-            break;
+                // set the destination instance id
+                _player->SetBattleGroundId(bg->GetInstanceID());
+                // set the destination team
+                _player->SetBGTeam(team);
+                // bg->HandleBeforeTeleportToBattleGround(_player);
+                sBattleGroundMgr.SendToBattleGround(_player, instanceId);
+                // add only in HandleMoveWorldPortAck()
+                // bg->AddPlayer(_player,team);
+                sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId);
+                break;
+            case 0:                                     // leave queue
+                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[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
+                // player left queue, we should update it, maybe now his group fits in
+                sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId,_player->GetBattleGroundQueueIdFromLevel(),arenatype,israted,rating);
+                SendPacket(&data);
+                sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetTypeID(),bgQueueTypeId);
+                break;
+            default:
+                sLog.outError("Battleground port: unknown action %u", action);
+                break;
+        }
     }
 }
 
@@ -384,7 +579,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());
@@ -392,15 +588,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);
                 }
             }
@@ -411,16 +617,36 @@
         // we should update all queues? .. i'm not sure if this code is correct
         for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
         {
-            if(uint32 queue_id = _player->GetBattleGroundQueueId(i))
+            uint32 queue_id = _player->GetBattleGroundQueueId(i);
+            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)
             {
-                if(BattleGround *bg = sBattleGroundMgr.GetBattleGround(queue_id))
-                {
-                    sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);
-                    SendPacket(&data);
-                }
+                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, arenatype, isRated);
+                SendPacket(&data);
+            }
         }
     }
+/*    else              // not sure if it needed...
+    {
+        for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+        {
+            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(),i , STATUS_NONE, 0, 0);
+            SendPacket(&data);
+        }
+    }*/
 }
 
 void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
@@ -480,16 +706,12 @@
     if(_player->InBattleGround())
         return;
 
-    for(int qId = 0; qId < PLAYER_MAX_BATTLEGROUND_QUEUES; ++qId)
-    {
-        if(_player->GetBattleGroundQueueId(qId) != 0)
-            return;
-    }
-
     uint64 guid;                                            // arena Battlemaster guid
     uint8 type;                                             // 2v2, 3v3 or 5v5
     uint8 asGroup;                                          // asGroup
     uint8 isRated;                                          // isRated
+    Group * grp;
+
     recv_data >> guid >> type >> asGroup >> isRated;
 
     Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
@@ -500,6 +722,7 @@
         return;
 
     uint8 arenatype = 0;
+    uint32 arenaRating = 0;
 
     switch(type)
     {
@@ -517,88 +740,196 @@
             return;
     }
 
-    if(isRated && !_player->GetArenaTeamId(type))           // player not in arena team of that size
+    //check existance
+    BattleGround* bg = NULL;
+    if( !(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)) )
     {
-        _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
+        sLog.outError("Battleground: template bg (all arenas) not found");     
         return;
     }
 
-    if(asGroup && !_player->GetGroup())                     // player not in group
-        return;
+    uint8 bgTypeId = bg->GetTypeID();
+    uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
 
-    // check existence
-    BattleGround *bg = sBattleGroundMgr.GetBattleGround(BATTLEGROUND_AA);
-    if(!bg)
-        return;
+    // check queueing conditions
+    if(!asGroup)
+    {
+        // check if already in queue
+        if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
+            //player is already in this queue
+            return;
+        // check if has free queue slots
+        if(!_player->HasFreeBattleGroundQueueId())
+            return;
+    }
+    else
+    {
+        grp = _player->GetGroup();
+        // no group found, error
+        if(!grp)
+            return;
+        uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, type);
+        switch(err)
+        {
+            // TODO: add error-based feedback to players in all cases
+        case BG_JOIN_ERR_GROUP_TOO_MANY:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_ARENA_GROUP_TOO_LARGE), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_ARENA_NOT_ENOUGH_PLAYERS), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_MIXED_ARENATEAM:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_ARENA_YOUR_TEAM_ONLY), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_OFFLINE_MEMBER:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_OFFLINE_MEMBER), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_MIXED_FACTION:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_FACTION), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_MIXED_LEVELS:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_LEVELS), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_GROUP_DESERTER:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_DESERTER), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+        case BG_JOIN_ERR_ALL_QUEUES_USED:
+            {
+            WorldPacket data;
+            ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS), NULL);
+            SendPacket(&data);
+            }
+            return;
+            break;
+            // all ok, can join
+        case BG_JOIN_ERR_OK:
+            break;
+            // not the above? shouldn't happen, don't let join
+        default:
+            return;
+            break;
+        };
+    }
 
-    bg->SetArenaType(arenatype);
-    bg->SetRated(isRated);
+    uint32 ateamId = 0;
 
-    if(asGroup && _player->GetGroup())
+    if(isRated)           
     {
-        Group *grp = _player->GetGroup();
+        ateamId = _player->GetArenaTeamId(type);
+        // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
+        ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);
+        if(!at)
+        {
+            _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
+            return;
+        }
+        // get the team rating for queueing
+        arenaRating = at->GetRating();
+        // the arenateam id must match for everyone in the group
+        // get the personal ratings for queueing
+        uint32 avg_pers_rating = 0;
         for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
         {
             Player *member = itr->getSource();
-            if(!member) continue;
 
-            /*if (!member->CanJoinToBattleground())
-                //player has deserter aura .. do nothing
-            */
+            // calc avg personal rating
+            avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (type*6) + 5);
+        }
 
-            if (member->InBattleGroundQueueForBattleGroundType(BATTLEGROUND_AA))
-                //player is already in this queue
-                continue;
+        if( arenatype )
+            avg_pers_rating /= arenatype;
 
-                                                            // add to queue
-            uint32 queueSlot = member->AddBattleGroundQueueId(BATTLEGROUND_AA);
-            if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
-            {
-                WorldPacket data;
-                //fill data
-                //member->GetSession()->SendPacket(data);
-                continue;
-            }
+        // if avg personal rating is more than 150 points below the team’s rating, the team will be queued against an opponent matching or similar to the average personal rating 
+        if(avg_pers_rating + 150 < arenaRating)
+            arenaRating = avg_pers_rating;
+    }
 
+    if(asGroup)
+    {
+        GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating, ateamId);
+        sLog.outDebug("Battleground: arena join as group start");
+        if(isRated)
+            sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(type),_player->GetName(),arenaRating,arenatype);
+        for(GroupReference *i