Index: src/shared/WheatyExceptionReport.cpp
===================================================================
--- src/shared/WheatyExceptionReport.cpp	(revision 5727)
+++ src/shared/WheatyExceptionReport.cpp	(working copy)
@@ -434,6 +434,124 @@
     _tprintf( _T("\r\n") );
 }
 
+//===========================================================================
+// Open the report file, and write the desired information to it.
+//===========================================================================
+void WheatyExceptionReport::GenerateDebugReport()
+{
+    TCHAR module_folder_name[MAX_PATH];
+    GetModuleFileName( 0, module_folder_name, MAX_PATH );
+    HMODULE hModule = GetModuleHandle(module_folder_name);
+
+    TCHAR* pos = _tcsrchr(module_folder_name, '\\');
+    if(!pos)
+        return;
+    pos[0] = '\0';
+    ++pos;
+
+    TCHAR crash_folder_path[MAX_PATH];
+    sprintf(crash_folder_path, "%s\\%s", module_folder_name, CrashFolder);
+    if(!CreateDirectory(crash_folder_path, NULL))
+    {
+        if(GetLastError() != ERROR_ALREADY_EXISTS)
+            return;
+    }
+
+    SYSTEMTIME systime;
+    GetLocalTime(&systime);
+    sprintf(m_szLogFileName, "%s\\%s_[%u-%u_%u-%u-%u].txt",
+        crash_folder_path, pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond
+        );
+
+    m_hReportFile = CreateFile( m_szLogFileName,
+        GENERIC_WRITE,
+        0,
+        0,
+        OPEN_ALWAYS,
+        FILE_FLAG_WRITE_THROUGH,
+        0 );
+
+    if ( !m_hReportFile )
+        return;
+
+    SetFilePointer( m_hReportFile, 0, 0, FILE_END );
+
+    // Start out with a banner
+    _tprintf(_T("Revision: %s\r\n"), SVN_REVISION);
+    _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);
+
+    PrintSystemInfo();
+
+    CONTEXT Ctx, *pCtx = &Ctx;
+    Ctx.ContextFlags = 0xFFFFFFFF;
+    BOOL ret = GetThreadContext(GetCurrentThread(), pCtx);
+
+    // Show the registers
+    #ifdef _M_IX86                                          // X86 Only!
+    _tprintf( _T("\r\nRegisters:\r\n") );
+
+    _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n")
+        ,pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
+        pCtx->Esi, pCtx->Edi );
+
+    _tprintf( _T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip );
+    _tprintf( _T("SS:ESP:%04X:%08X  EBP:%08X\r\n"),
+        pCtx->SegSs, pCtx->Esp, pCtx->Ebp );
+    _tprintf( _T("DS:%04X  ES:%04X  FS:%04X  GS:%04X\r\n"),
+        pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs );
+    _tprintf( _T("Flags:%08X\r\n"), pCtx->EFlags );
+    #endif
+
+    #ifdef _M_X64
+    _tprintf( _T("\r\nRegisters:\r\n") );
+    _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n")
+        _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n")
+        ,pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx,
+        pCtx->Rsi, pCtx->Rdi ,pCtx->R9,pCtx->R10,pCtx->R11,pCtx->R12,pCtx->R13,pCtx->R14,pCtx->R15);
+    _tprintf( _T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip );
+    _tprintf( _T("SS:RSP:%04X:%016X  RBP:%08X\r\n"),
+        pCtx->SegSs, pCtx->Rsp, pCtx->Rbp );
+    _tprintf( _T("DS:%04X  ES:%04X  FS:%04X  GS:%04X\r\n"),
+        pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs );
+    _tprintf( _T("Flags:%08X\r\n"), pCtx->EFlags );
+    #endif
+
+    SymSetOptions( SYMOPT_DEFERRED_LOADS );
+
+    // Initialize DbgHelp
+    if ( !SymInitialize( GetCurrentProcess(), 0, TRUE ) )
+    {
+        _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"),
+            ErrorMessage(GetLastError()));
+    }
+
+    CONTEXT trashableContext = *pCtx;
+
+    WriteStackDetails( &trashableContext, false );
+
+//    #ifdef _M_IX86                                          // X86 Only!
+
+    _tprintf( _T("========================\r\n") );
+    _tprintf( _T("Local Variables And Parameters\r\n") );
+
+    trashableContext = *pCtx;
+    WriteStackDetails( &trashableContext, true );
+
+    _tprintf( _T("========================\r\n") );
+    _tprintf( _T("Global Variables\r\n") );
+
+    /* the following crashes :-/
+    SymEnumSymbols( GetCurrentProcess(),
+        (DWORD64)hModule,
+        0, EnumerateSymbolsCallback, 0 );*/
+  //  #endif                                                  // X86 Only!
+
+    _tprintf( _T("\r\n") );
+    
+    CloseHandle( m_hReportFile );
+    m_hReportFile = 0;
+}
+
 //======================================================================
 // Given an exception code, returns a pointer to a static string with a
 // description of the exception
Index: src/shared/WheatyExceptionReport.h
===================================================================
--- src/shared/WheatyExceptionReport.h	(revision 5727)
+++ src/shared/WheatyExceptionReport.h	(working copy)
@@ -79,6 +79,8 @@
         static LONG WINAPI WheatyUnhandledExceptionFilter(
             PEXCEPTION_POINTERS pExceptionInfo );
 
+        static void GenerateDebugReport();
+
     private:
 
         // where report info is extracted and generated
Index: src/shared/Database/DBCfmt.cpp
===================================================================
--- src/shared/Database/DBCfmt.cpp	(revision 5727)
+++ src/shared/Database/DBCfmt.cpp	(working copy)
@@ -48,7 +48,7 @@
 const char ItemRandomSuffixfmt[]="nxxxxxxxxxxxxxxxxxxiiiiii";
 const char ItemSetEntryfmt[]="dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii";
 const char LockEntryfmt[]="niiiiixxxiiiiixxxiixxxxxxxxxxxxxx";
-const char MapEntryfmt[]="nxixssssssssssssssssxxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxi";
+const char MapEntryfmt[]="nxixssssssssssssssssxxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxiixxi";
 const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii";
 const char SkillLinefmt[]="nixssssssssssssssssxxxxxxxxxxxxxxxxxxi";
 const char SkillLineAbilityfmt[]="xiniixxiiiiixxi";
Index: src/shared/Database/Database.h
===================================================================
--- src/shared/Database/Database.h	(revision 5727)
+++ src/shared/Database/Database.h	(working copy)
@@ -71,6 +71,7 @@
         virtual bool Execute(const char *sql) = 0;
         bool PExecute(const char *format,...) ATTR_PRINTF(2,3);
         virtual bool DirectExecute(const char* sql) = 0;
+        bool DirectPExecute(const char *format,...) ATTR_PRINTF(2,3);
 
         // Writes SQL commands to a LOG file (see mangosd.conf "LogSQL")
         bool PExecuteLog(const char *format,...) ATTR_PRINTF(2,3);
Index: src/shared/Database/Database.cpp
===================================================================
--- src/shared/Database/Database.cpp	(revision 5727)
+++ src/shared/Database/Database.cpp	(working copy)
@@ -149,3 +149,24 @@
 
     return Execute(szQuery);
 }
+
+bool Database::DirectPExecute(const char * format,...)
+{
+    if (!format)
+        return false;
+
+    va_list ap;
+    char szQuery [MAX_QUERY_LEN];
+    va_start(ap, format);
+    int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+    va_end(ap);
+
+    if(res==-1)
+    {
+        sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+        return false;
+    }
+
+    return DirectExecute(szQuery);
+}
+
Index: src/shared/Database/DBCStructure.h
===================================================================
--- src/shared/Database/DBCStructure.h	(revision 5727)
+++ src/shared/Database/DBCStructure.h	(working copy)
@@ -360,6 +360,15 @@
                                                             // 19-32, not used
 };
 
+enum MapTypes
+{
+    MAP_COMMON          = 0,
+    MAP_INSTANCE        = 1,
+    MAP_RAID            = 2,
+    MAP_BATTLEGROUND    = 3,
+    MAP_ARENA           = 4
+};
+
 struct MapEntry
 {
     uint32      MapID;                                      // 0
@@ -387,7 +396,14 @@
     int32       parent_map;                                 // 117 map_id of parent map
     //float start_x                                         // 118 enter x coordinate (if exist single entry)
     //float start_y                                         // 119 enter y coordinate (if exist single entry)
-                                                            // 120-123
+    uint32 resetTimeRaid;                                   // 120
+    uint32 resetTimeHeroic;                                 // 121
+                                                            // 122
+
+    inline bool IsDungeon() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID; }
+    inline bool SupportsHeroicMode() const { return resetTimeHeroic && !resetTimeRaid; }
+    inline bool HasResetTime() const { return resetTimeHeroic || resetTimeRaid; }
+
     uint32      addon;                                      // 124 (0-original maps,1-tbc addon)
 };
 
Index: src/shared/Database/SQLStorage.cpp
===================================================================
--- src/shared/Database/SQLStorage.cpp	(revision 5727)
+++ src/shared/Database/SQLStorage.cpp	(working copy)
@@ -28,9 +28,9 @@
 #endif
 
 const char CreatureInfofmt[]="iiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiliiiiiiiiiiiiiiiisiilliis";
-const char CreatureDataAddonInfofmt[]="iiiiiis";
+const char CreatureDataAddonInfofmt[]="iiiiiiis";
 const char CreatureModelfmt[]="iffbi";
-const char CreatureInfoAddonInfofmt[]="iiiiiis";
+const char CreatureInfoAddonInfofmt[]="iiiiiiis";
 const char EquipmentInfofmt[]="iiiiiiiiii";
 const char GameObjectInfofmt[]="iiissiifiiiiiiiiiiiiiiiiiiiiiiiis";
 const char ItemPrototypefmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiffiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifsiiiii";
Index: src/mangosd/mangosd.conf.in
===================================================================
--- src/mangosd/mangosd.conf.in	(revision 5727)
+++ src/mangosd/mangosd.conf.in	(working copy)
@@ -325,6 +325,15 @@
 #        Default: 0 (false)
 #                 1 (true)
 #
+#    Instance.ResetTimeHour
+#        The hour of the day (0-23) when the global instance resets occur.
+#        Default: 4
+#
+#    Instance.UnloadDelay
+#        Unload the instance map from memory after some time if no players are inside.
+#        Default: 1800000 (miliseconds, i.e 30 minutes)
+#                 0 (instance maps are kept in memory until they are reset)
+#
 #    Quests.LowLevelHideDiff
 #        Quest level difference to hide for player low level quests: 
 #        if player_level > quest_level + LowLevelQuestsHideDiff then quest "!" mark not show for quest giver
@@ -383,6 +392,8 @@
 CastUnstuck = 1
 Instance.IgnoreLevel = 0
 Instance.IgnoreRaid = 0
+Instance.ResetTimeHour = 4;
+Instance.UnloadDelay = 1800000;
 Quests.LowLevelHideDiff = 4
 Quests.HighLevelHideDiff = 7
 MaxPrimaryTradeSkill = 2
@@ -660,6 +671,10 @@
 #         Reputation Gain rate
 #         Default: 1
 #
+#    Rate.InstanceResetTime
+#        Multiplier for the number of days in between global raid/heroic instance resets.
+#        Default: 1
+#
 #    SkillChance.Orange
 #    SkillChance.Yellow
 #    SkillChance.Green
@@ -714,6 +729,7 @@
 Rate.Mining.Next   = 1
 Rate.Talent = 1
 Rate.Reputation.Gain = 1
+Rate.InstanceResetTime = 1
 SkillChance.Orange = 100
 SkillChance.Yellow = 75
 SkillChance.Green  = 25
Index: src/mangosd/Makefile.am
===================================================================
--- src/mangosd/Makefile.am	(revision 5727)
+++ 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/Object.cpp
===================================================================
--- src/game/Object.cpp	(revision 5727)
+++ src/game/Object.cpp	(working copy)
@@ -946,7 +946,8 @@
 
 InstanceData* WorldObject::GetInstanceData()
 {
-    return MapManager::Instance().GetMap(m_mapId, this)->GetInstanceData();
+    Map *map = MapManager::Instance().GetMap(m_mapId, this);
+    return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL;
 }
 
                                                             //slow
Index: src/game/MapInstanced.h
===================================================================
--- src/game/MapInstanced.h	(revision 5727)
+++ src/game/MapInstanced.h	(working copy)
@@ -20,10 +20,13 @@
 #define MANGOS_MAP_INSTANCED_H
 
 #include "Map.h"
+#include "MapInstancedSaveMgr.h"
 
 class MANGOS_DLL_DECL MapInstanced : public Map
 {
+    friend class MapManager;
     public:
+        typedef HM_NAMESPACE::hash_map< uint32, Map* > InstancedMaps;
 
         MapInstanced(uint32 id, time_t, uint32 aInstanceId);
         ~MapInstanced() {}
@@ -34,8 +37,9 @@
         virtual void UnloadAll(bool pForce);
 
         Map* GetInstance(const WorldObject* obj);
-        bool IsValidInstance(uint32 InstanceId);
-
+        Map* FindMap(uint32 InstanceId) { return _FindMap(InstanceId); }
+        void DestroyInstance(uint32 InstanceId);
+        void DestroyInstance(InstancedMaps::iterator &itr);
         void AddGridMapReference(const GridPair &p) { ++GridMapReference[p.x_coord][p.y_coord]; }
         void RemoveGridMapReference(const GridPair &p)
         {
@@ -43,12 +47,12 @@
             if (!GridMapReference[p.x_coord][p.y_coord]) { SetUnloadFlag(GridPair(63-p.x_coord,63-p.y_coord), true); }
         }
 
+        InstancedMaps &GetInstancedMaps() { return m_InstancedMaps; }
+
     private:
 
-        void CreateInstance(uint32 InstanceId, Map* &map);
+        InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty);
 
-        typedef HM_NAMESPACE::hash_map< uint32, Map* > InstancedMaps;
-
         InstancedMaps m_InstancedMaps;
 
         Map* _FindMap(uint32 InstanceId)
Index: src/game/Creature.h
===================================================================
--- src/game/Creature.h	(revision 5727)
+++ src/game/Creature.h	(working copy)
@@ -227,7 +227,7 @@
 struct CreatureData
 {
     uint32 id;                                              // entry in creature_template
-    uint32 mapid;
+    uint16 mapid;
     uint32 displayid;
     int32 equipmentId;
     float posX;
@@ -245,6 +245,7 @@
     uint32 curmana;
     bool  is_dead;
     uint8 movementType;
+    uint8 spawnMask;
 };
 
 struct CreatureDataAddonAura
@@ -257,6 +258,7 @@
 struct CreatureDataAddon
 {
     uint32 guidOrEntry;
+    uint32 path_id;
     uint32 mount;
     uint32 bytes0;
     uint32 bytes1;
@@ -461,8 +463,9 @@
         void setDeathState(DeathState s);                   // overwrite virtual Unit::setDeathState
 
         bool LoadFromDB(uint32 guid, uint32 InstanceId);
-        virtual void SaveToDB();                            // overwrited in Pet
-        virtual void DeleteFromDB();                        // overwrited in Pet
+        void SaveToDB();
+        virtual void SaveToDB(uint32 mapid, uint8 spawnMask); // overwrited in Pet
+        virtual void DeleteFromDB();                          // overwrited in Pet
 
         Loot loot;
         bool lootForPickPocketed;
@@ -495,6 +498,7 @@
         void RemoveCorpse();
 
         time_t const& GetRespawnTime() const { return m_respawnTime; }
+        time_t GetRespawnTimeEx();
         void SetRespawnTime(uint32 respawn) { m_respawnTime = respawn ? time(NULL) + respawn : 0; }
         void Respawn();
         void SaveRespawnTime();
@@ -524,6 +528,8 @@
                 return m_charmInfo->GetCharmSpell(pos)->spellId;
         }
 
+        uint32 GetWaypointPath();
+
     protected:
         // vendor items
         typedef std::vector<CreatureItem> CreatureItems;
Index: src/game/Chat.h
===================================================================
--- src/game/Chat.h	(revision 5727)
+++ src/game/Chat.h	(working copy)
@@ -338,6 +338,7 @@
         bool HandleComeToMeCommand(const char *args);
 
         //! Development Commands
+        bool HandleInstanceCommand(const char* args);
         bool HandleSetValue(const char* args);
         bool HandleGetValue(const char* args);
         bool HandleSet32Bit(const char* args);
Index: src/game/Level1.cpp
===================================================================
--- src/game/Level1.cpp	(revision 5727)
+++ src/game/Level1.cpp	(working copy)
@@ -30,6 +30,7 @@
 #include "ObjectAccessor.h"
 #include "Language.h"
 #include "CellImpl.h"
+#include "MapInstancedSaveMgr.h"
 #ifdef _DEBUG_VMAPS
 #include "VMapFactory.h"
 #endif
@@ -428,12 +429,22 @@
                 }
             }
 
-            // bind us to the players instance
-            BoundInstancesMap::iterator i = chr->m_BoundInstances.find(chr->GetMapId());
-                                                            // error, the player has no instance bound!!!
-            if (i == chr->m_BoundInstances.end()) return true;
-            _player->m_BoundInstances[chr->GetMapId()] = std::pair < uint32, uint32 >(i->second.first, i->second.second);
-            _player->SetInstanceId(chr->GetInstanceId());
+            // if the player or the player's group is bound to another instance
+            // the player will not be bound to another one
+            InstancePlayerBind *pBind = _player->GetBoundInstance(chr->GetMapId(), chr->GetDifficulty());
+            if(!pBind)
+            {
+                Group *group = _player->GetGroup();
+                InstanceGroupBind *gBind = group ? group->GetBoundInstance(chr->GetMapId(), chr->GetDifficulty()) : NULL;
+                if(!gBind)
+                {
+                    // if no bind exists, create a solo bind
+                    InstanceSave *save = sInstanceSaveManager.GetInstanceSave(chr->GetInstanceId());
+                    if(save) _player->BindToInstance(save, false);
+                }
+            }
+
+            _player->SetDifficulty(chr->GetDifficulty());
         }
 
         PSendSysMessage(LANG_APPEARING_AT, chr->GetName());
Index: src/game/MovementHandler.cpp
===================================================================
--- src/game/MovementHandler.cpp	(revision 5727)
+++ src/game/MovementHandler.cpp	(working copy)
@@ -28,25 +28,29 @@
 #include "Transports.h"
 #include "BattleGround.h"
 #include "WaypointMovementGenerator.h"
+#include "MapInstancedSaveMgr.h"
 
 void WorldSession::HandleMoveWorldportAckOpcode( WorldPacket & /*recv_data*/ )
 {
     sLog.outDebug( "WORLD: got MSG_MOVE_WORLDPORT_ACK." );
 
     MapEntry const* mEntry = sMapStore.LookupEntry(GetPlayer()->GetMapId());
+    InstanceTemplate const* mInstance = objmgr.GetInstanceTemplate(GetPlayer()->GetMapId());
     if(!mEntry || !MaNGOS::IsValidMapCoord(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY()))
     {
         LogoutPlayer(false);
         return;
     }
 
-    // reset instance validity
-    GetPlayer()->m_InstanceValid = true;
+    // reset instance validity, except if going to an instance inside an instance
+    if(GetPlayer()->m_InstanceValid == false && !mInstance)
+        GetPlayer()->m_InstanceValid = true;
 
     GetPlayer()->SetSemaphoreTeleport(false);
 
     GetPlayer()->SendInitialPacketsBeforeAddToMap();
-    MapManager::Instance().GetMap(GetPlayer()->GetMapId(), GetPlayer())->Add(GetPlayer());
+    bool success = MapManager::Instance().GetMap(GetPlayer()->GetMapId(), GetPlayer())->Add(GetPlayer());
+    assert(success);
     GetPlayer()->SendInitialPacketsAfterAddToMap();
 
     // flight fast teleport case
@@ -83,6 +87,15 @@
         }
     }
 
+    if(mEntry->map_type == MAP_RAID && mInstance)
+    {
+        if(GetPlayer()->GetBoundInstance(GetPlayer()->GetMapId(), GetPlayer()->GetDifficulty()) == NULL)
+        {
+            uint32 timeleft = sInstanceSaveManager.GetResetTimeFor(GetPlayer()->GetMapId()) - time(NULL);
+            GetPlayer()->SendInstanceResetWarning(GetPlayer()->GetMapId(), timeleft); // greeting at the entrance of the resort raid instance
+        }
+    }
+
     // mount allow check
     if(!_player->GetBaseMap()->IsMountAllowed())
         _player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
@@ -511,3 +524,5 @@
 }
 
 
+
+
Index: src/game/WaypointMovementGenerator.cpp
===================================================================
--- src/game/WaypointMovementGenerator.cpp	(revision 5727)
+++ src/game/WaypointMovementGenerator.cpp	(working copy)
@@ -16,296 +16,254 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-/*
-creature_movement Table
-
-alter table creature_movement add `text1` varchar(255) default NULL;
-alter table creature_movement add `text2` varchar(255) default NULL;
-alter table creature_movement add `text3` varchar(255) default NULL;
-alter table creature_movement add `text4` varchar(255) default NULL;
-alter table creature_movement add `text5` varchar(255) default NULL;
-alter table creature_movement add `emote` int(10) unsigned default '0';
-alter table creature_movement add `spell` int(5) unsigned default '0';
-alter table creature_movement add `wpguid` int(11) default '0';
-
-*/
-
 #include <ctime>
 
+//Basic headers
 #include "WaypointMovementGenerator.h"
+//Accessors
+#include "Database/DatabaseEnv.h"
 #include "ObjectMgr.h"
+#include "World.h"
+//Creature-specific headers
 #include "Creature.h"
-#include "DestinationHolderImp.h"
 #include "CreatureAI.h"
+//Player-Specific
+#include "Player.h"
+//Visual
+#include "ProgressBar.h"
 
-#include <cassert>
+WaypointStore sWaypointStore;
 
 //-----------------------------------------------//
-void
-WaypointMovementGenerator<Creature>::LoadPath(Creature &c)
+void WaypointStore::Free()
 {
-    QueryResult *result = NULL;
-    sLog.outDebug("DEBUG: WaypointMovementGenerator::_load: GUID - %d", c.GetGUIDLow());
-    // Identify by GUID
-    result = WorldDatabase.PQuery("SELECT position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, text1, text2, text3, text4, text5 FROM creature_movement WHERE id = '%u' ORDER BY point", c.GetDBTableGUIDLow());
-    /*
-    if( result ) {
-    sLog.outDebug("DEBUG: Number of hits: %d", result->GetRowCount());
-    } else {
-    sLog.outDebug("DEBUG: Nothing found");
+    for(uint32 i = 0;i < records;++i)
+    {
+        if(data[i])
+            for(WaypointPath::iterator itr = data[i]->begin(); itr!= data[i]->end(); ++ itr)
+               delete (*itr);
+        data[i]->clear();
+        delete data[i];
     }
-    */
+    delete [] data;
+}
 
-    if( result )
+void WaypointStore::Load()
+{
+    QueryResult *result = WorldDatabase.PQuery("SELECT MAX(`id`) FROM `waypoint_data");
+    if(!result)
     {
-        unsigned int count = 0;
-        const unsigned int sz = result->GetRowCount();
-        i_path.Resize( sz );
-        i_delays.resize( sz );
-        i_wpBehaviour.resize( sz );
+        sLog.outError(" an error occured while loading the table `waypoint_data` ( maybe it doesn't exist ?)\n");
+        exit(1);                                            // Stop server at loading non exited table or not accessable table
+    }
 
-        do
+    records = (*result)[0].GetUInt32();
+    delete result;
+
+    result = WorldDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_flag`,`event_id`,`event_chance` FROM `waypoint_data` ORDER BY `id`, `point`");
+    if(!result)
+    {
+        sLog.outErrorDb("The table `creature_addon` is empty or corrupted");
+        return;
+    }
+
+    data = new WaypointPath*[records];
+    uint32 total_records = result->GetRowCount();
+
+    barGoLink bar( total_records);
+    Field *fields;
+    uint32 last_id = 0;
+    do
+    {
+        fields = result->Fetch();
+        uint32 id = fields[0].GetUInt32();
+        bar.step();
+        WaypointData *wp = new WaypointData;
+
+        if(last_id != id)
         {
-            //sLog.outDebug("DEBUG: _load");
-            Field *fields = result->Fetch();
-            i_path[count].x         = fields[0].GetFloat();
-            i_path[count].y         = fields[1].GetFloat();
-            i_path[count].z         = fields[2].GetFloat();
-            float orientation       = fields[3].GetFloat();
-            uint32 model1           = fields[4].GetUInt32();
-            uint32 model2           = fields[5].GetUInt32();
-            i_delays[count]         = fields[6].GetUInt16();
-            uint32 emote            = fields[7].GetUInt32();
-            uint32 spell            = fields[8].GetUInt32();
-            std::string text1       = fields[9].GetCppString();
-            std::string text2       = fields[10].GetCppString();
-            std::string text3       = fields[11].GetCppString();
-            std::string text4       = fields[12].GetCppString();
-            std::string text5       = fields[13].GetCppString();
+            data[id] = new WaypointPath;
+        }
 
-            if( (emote != 0) || (spell != 0)
-                || !text1.empty() || !text2.empty() || !text3.empty() || !text4.empty() || !text5.empty()
-                || (model1 != 0)  || (model2 != 0) || (orientation != 100))
-            {
-                WaypointBehavior *tmpWPB = new WaypointBehavior;
+        float x,y,z;
+        x = fields[2].GetFloat();
+        y = fields[3].GetFloat();
+        z = fields[4].GetFloat();
 
-                // sLog.outDebug("DEBUG: _load  ---  Adding WaypointBehavior");
+        MaNGOS::NormalizeMapCoord(x);
+        MaNGOS::NormalizeMapCoord(y);
 
-                tmpWPB->text[0] = text1;
-                tmpWPB->text[1] = text2;
-                tmpWPB->text[2] = text3;
-                tmpWPB->text[3] = text4;
-                tmpWPB->text[4] = text5;
-                tmpWPB->orientation = orientation;
-                tmpWPB->emote = emote;
-                tmpWPB->spell = spell;
-                tmpWPB->model1 = model1;
-                tmpWPB->model2 = model2;
-                tmpWPB->HasDone = false;
-                i_wpBehaviour[count] = tmpWPB;
-            }
-            else
-            {
-                i_wpBehaviour[count] = NULL;
-            }
+        wp->id = fields[1].GetUInt32();
+        wp->x = x;
+        wp->y = y;
+        wp->z = z;
+        wp->run = fields[5].GetBool();
+        wp->delay = fields[6].GetUInt32();
+        wp->event_id = fields[7].GetUInt32();
+        wp->event_chance = fields[8].GetUInt8();
 
-            if(!MaNGOS::IsValidMapCoord(i_path[count].x,i_path[count].y))
-            {
-                sLog.outErrorDb("ERROR: Creature (guidlow %d,entry %d) have invalid coordinates in his waypoint %d (X: %d, Y: %d).",
-                    c.GetGUIDLow(),c.GetEntry(),count,i_path[count].x,i_path[count].y
-                    );
+        data[id]->push_back(wp);
 
-                // prevent invalid coordinates using
-                MaNGOS::NormalizeMapCoord(i_path[count].x);
-                MaNGOS::NormalizeMapCoord(i_path[count].y);
-                i_path[count].z = MapManager::Instance ().GetBaseMap(c.GetMapId())->GetHeight(i_path[count].x,i_path[count].y, i_path[count].z);
-            }
-            // to prevent a misbehaviour inside "update"
-            // update is alway called with the next wp - but the wpSys needs the current
-            // so when the routine is called the first time, wpSys gets the last waypoint
-            // and this prevents the system from performing text/emote, etc
-            if( count == (sz-1) )
-            {
-                if( i_wpBehaviour[count] != NULL )
-                {
-                    i_wpBehaviour[count]->HasDone = true;
-                }
-            }
-            //if( i_delays[count] < 30 /* millisecond */ )
-            //    i_delays[count] = (rand() % 5000);
-            ++count;
+        last_id = id;
 
-        } while( result->NextRow() );
+    } while( result->NextRow() );
 
-        delete result;
+    delete result;
+}
+WaypointData* CreateWaypoint(uint32 id, float x, float y, float z, bool run, uint32 delay, uint32 event_id, uint8 event_chance)
+{
+    WaypointData *wp = new WaypointData;
+    wp->id = id;
+    
+    MaNGOS::NormalizeMapCoord(x);
+    MaNGOS::NormalizeMapCoord(y);
 
-        assert( sz == count );
-    }
+    wp->x = x;
+    wp->y = y;
+    wp->z = z;
+    
+    wp->run = run;
+    wp->delay = delay;
+    wp->event_id = event_id;
+    wp->event_chance = event_chance;
+
+    return wp;
 }
 
+template<class T>
 void
-WaypointMovementGenerator<Creature>::ClearWaypoints()
+WaypointMovementGenerator<T>::Initialize(T &u)
 {
-    for (std::vector<WaypointBehavior*>::iterator itr = i_wpBehaviour.begin(); itr != i_wpBehaviour.end(); ++itr)
-        delete (*itr);
-    i_wpBehaviour.clear();
+    i_currentNode = 0;
+    i_nextMoveTime.Reset(0);
+    u.StopMoving();
+    if(!path_id)
+        GeneratePathId(u);
+    waypoints = sWaypointStore.GetPath(path_id);
 }
 
+template<class T>
 void
-WaypointMovementGenerator<Creature>::Initialize()
+WaypointMovementGenerator<T>::Reset(T &u)
 {
-    QueryResult *result = WorldDatabase.Query("SELECT distinct(id) as uniqueid FROM creature_movement");
+    u.StopMoving();
+    
+    float x,y,z;
+    i_destinationHolder.GetLocationNow(x,y,z);
 
-    if( result )
-    {
-        do
-        {
-            Field *fields = result->Fetch();
-            si_waypointHolders.insert( fields[0].GetUInt32() );
-        }
-        while( result->NextRow() );
+    Traveller<T> traveller(u);
+    i_destinationHolder.GetDestination(x,y,z);
+    i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
+}
 
-        delete result;
-    }
+template<class T>
+void
+WaypointMovementGenerator<T>::GeneratePathId(T &unit)
+{
+    path_id = 0;
 }
 
+template<>
+void
+WaypointMovementGenerator<Creature>::GeneratePathId(Creature &unit)
+{
+    path_id = unit.GetWaypointPath();
+}
+
+template<class T>
+void
+WaypointMovementGenerator<T>::SetMoveFlag(T &unit, bool flag)
+{
+    //I wonder how that should even work for players, empty for now
+}
+
+template<>
+void
+WaypointMovementGenerator<Creature>::SetMoveFlag(Creature &unit,bool flag)
+{
+    
+}
+
+template<class T>
+void
+WaypointMovementGenerator<T>::MovementInform(T &unit)
+{
+
+}
+
+template<>
+void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
+{
+    unit.AI()->MovementInform(path_id);
+}
+
+template<class T>
 bool
-WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
+WaypointMovementGenerator<T>::Update(T &unit, const uint32 &diff)
 {
-    if(!&creature)
+    if(!&unit)
         return true;
 
     // Waypoint movement can be switched on/off
     // This is quite handy for escort quests and other stuff
 
-    if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED))
+    if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED))
         return true;
 
-    // prevent crash at empty waypoint path.
-    if(i_path.Empty())
-    {
-        return true;
-    }
+    // Clear the generator if the path doesn't exist
+    if(!waypoints || !waypoints->size())
+        return false;
 
-    CreatureTraveller traveller(creature);
+    Traveller<T> traveller(unit);
 
-    /*
-    if( npcIsStopped[creature.GetGUID()] )
-    {
-        i_nextMoveTime.Update(40000);
-        i_destinationHolder.UpdateTraveller(traveller, ((diff)-40000), false);
-        npcIsStopped[creature.GetGUID()] = false;
-        return true;
-    }
-    */
     i_nextMoveTime.Update(diff);
     i_destinationHolder.UpdateTraveller(traveller, diff, false);
 
-    if( creature.IsStopped() )
-    {
-        uint32 wpB = i_currentNode > 0 ? i_currentNode-1 : i_wpBehaviour.size()-1;
-
-        if( i_wpBehaviour[wpB] != NULL )
-        {
-            struct WaypointBehavior *tmpBehavior = i_wpBehaviour[wpB];
-
-            if (!tmpBehavior->HasDone)
-            {
-                if(tmpBehavior->emote != 0)
-                {
-                    creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,tmpBehavior->emote);
-                }
-                //sLog.outDebug("DEBUG: tmpBehavior->text[0] TEST");
-                if(!tmpBehavior->text[0].empty())
-                {
-                    //sLog.outDebug("DEBUG: tmpBehavior->text[0] != \"\"");
-                    // Only one text is set
-                    if( tmpBehavior->text[1].empty() )
-                    {
-                        //sLog.outDebug("DEBUG: tmpBehavior->text[1] == NULL");
-                        creature.Say(tmpBehavior->text[0].c_str(), 0, 0);
-                    }
-                    else
-                    {
-                        // Select one from max 5 texts (0 and 1 laready checked)
-                        int i = 2;
-                        for( ; i < 5; ++i )
-                            if( tmpBehavior->text[i].empty() )
-                                break;
-
-                        //sLog.outDebug("DEBUG: tmpBehavior->text[i] == \"\": %d", i);
-                        //sLog.outDebug("DEBUG: rand() % (i): %d", rand() % (i));
-
-                        creature.Say(tmpBehavior->text[rand() % i].c_str(), 0, 0);
-                    }
-                }
-                if(tmpBehavior->spell != 0)
-                {
-                    //sLog.outDebug("DEBUG: wpSys - spell");
-                    creature.CastSpell(&creature,tmpBehavior->spell, false);
-                }
-                if (tmpBehavior->orientation !=100)
-                {
-                    //sLog.outDebug("DEBUG: wpSys - orientation");
-                    creature.SetOrientation(tmpBehavior->orientation);
-                }
-                if(tmpBehavior->model1 != 0)
-                {
-                    //sLog.outDebug("DEBUG: wpSys - model1");
-                    creature.SetDisplayId(tmpBehavior->model1);
-                }
-                tmpBehavior->HasDone = true;
-                MovementInform(creature);
-            }                                               // HasDone == false
-        }                                                   // wpBehaviour found
-    }                                                       // i_creature.IsStopped()
-
     if( i_nextMoveTime.Passed() )
     {
-        if( creature.IsStopped() )
+        if( unit.IsStopped() )
         {
-            assert( i_currentNode < i_path.Size() );
-            creature.addUnitState(UNIT_STAT_ROAMING);
-            const Path::PathNode &node(i_path(i_currentNode));
-            i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
-            i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
-            uint32 wpB = i_currentNode > 0 ? i_currentNode-1 : i_wpBehaviour.size()-1;
-
-            if( i_wpBehaviour[wpB] != NULL )
+            if(i_currentNode == waypoints->size() - 1) //If that's our last waypoint
             {
-                struct WaypointBehavior *tmpBehavior = i_wpBehaviour[wpB];
-                tmpBehavior->HasDone = false;
-                if(tmpBehavior->model2 != 0)
-                {
-                    creature.SetDisplayId(tmpBehavior->model2);
-                }
-                if (tmpBehavior->orientation !=100)
-                {
-                    creature.SetOrientation(tmpBehavior->orientation);
-                }
-                creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
+                MovementInform(unit);
+                if(repeating) //If the movement is repeating
+                    i_currentNode = 0; //Start moving all over again
+                else
+                    return false; //Clear the waypoint movement
             }
+            else
+                i_currentNode++;
+
+            WaypointData const *nextWP = *(waypoints->begin()+i_currentNode);
+            SetMoveFlag(unit, nextWP->run);
+            unit.addUnitState(UNIT_STAT_ROAMING);
+            i_destinationHolder.SetDestination(traveller, nextWP->x, nextWP->y, nextWP->z);
+            i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());            
         }
         else
         {
-            creature.StopMoving();
-            i_nextMoveTime.Reset(i_delays[i_currentNode]);
-            ++i_currentNode;
-            if( i_currentNode >= i_path.Size() )
-                i_currentNode = 0;
+            WaypointData *wp = *(waypoints->begin()+i_currentNode);
+            i_nextMoveTime.Reset(wp->delay);
+
+            if(wp->event_id && rand()%100 < wp->event_chance)
+                sWorld.ScriptsStart(sWaypointScripts, wp->event_id, &unit, NULL);
+
+            unit.StopMoving();
         }
     }
     return true;
 }
 
-void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
-{
-    if(unit.AI())
-        unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
-}
+template void WaypointMovementGenerator<Player>::Initialize(Player &);
+template void WaypointMovementGenerator<Creature>::Initialize(Creature &);
+template void WaypointMovementGenerator<Player>::Reset(Player &);
+template void WaypointMovementGenerator<Creature>::Reset(Creature &);
+template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32 &);
+template bool WaypointMovementGenerator<Creature>::Update(Creature &, const uint32 &);
+template void WaypointMovementGenerator<Player>::GeneratePathId(Player &);
+template void WaypointMovementGenerator<Player>::MovementInform(Player &);
+template void WaypointMovementGenerator<Player>::SetMoveFlag(Player &, bool flag);
 
-std::set<uint32> WaypointMovementGenerator<Creature>::si_waypointHolders;
-
 //----------------------------------------------------//
 void
 FlightPathMovementGenerator::LoadPath(Player &)
@@ -404,6 +362,43 @@
     }
 }
 
+//----- Point Movement Generator
+template<class T>
+bool
+PointMovementGenerator<T>::Update(T &unit, const uint32 &diff)
+{
+    if(!&unit)
+        return false;
+
+    if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED))
+        return true;
+
+    Traveller<T> traveller(unit);
+
+    i_destinationHolder.UpdateTraveller(traveller, diff, false);
+
+    if(i_destinationHolder.HasArrived())
+    {
+        unit.StopMoving();
+        MovementInform(unit);
+        return false;    
+    }
+
+    return true;
+}
+
+template<class T>
+void
+PointMovementGenerator<T>::Initialize(T &unit)
+{
+    unit.StopMoving();
+    Traveller<T> traveller(unit);
+    i_destinationHolder.SetDestination(traveller,x,y,z);
+}
+
+template void PointMovementGenerator<Player>::Initialize(Player &);
+template bool PointMovementGenerator<Player>::Update(Player &, const uint32 &);
+
 //
 // Unique1's ASTAR Pathfinding Code... For future use & reference...
 //
Index: src/game/GameObject.h
===================================================================
--- src/game/GameObject.h	(revision 5727)
+++ src/game/GameObject.h	(working copy)
@@ -197,6 +197,7 @@
     int32  spawntimesecs;
     uint32 animprogress;
     uint32 go_state;
+    uint8 spawnMask;
 };
 
 // GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
@@ -255,6 +256,7 @@
         void Whisper(const uint64 receiver, const char* text) { MonsterWhisper(receiver,text); }
 
         void SaveToDB();
+        void SaveToDB(uint32 mapid, uint8 spawnMask);
         bool LoadFromDB(uint32 guid, uint32 InstanceId);
         void DeleteFromDB();
         void SetLootState(LootState s) { m_lootState = s; }
Index: src/game/MapManager.h
===================================================================
--- src/game/MapManager.h	(revision 5727)
+++ src/game/MapManager.h	(working copy)
@@ -37,9 +37,11 @@
     public:
 
         Map* GetMap(uint32, const WorldObject* obj);
+        Map* FindMap(uint32 mapid) { return _findMap(mapid); }
 
         // only const version for outer users
         Map const* GetBaseMap(uint32 id) const { return const_cast<MapManager*>(this)->_GetBaseMap(id); }
+        void DeleteInstance(uint32 mapid, uint32 instanceId, uint8 mode);
 
         inline uint16 GetAreaFlag(uint32 mapid, float x, float y) const
         {
@@ -91,6 +93,10 @@
         inline uint32 GenerateInstanceId() { return ++i_MaxInstanceId; }
         void InitMaxInstanceId();
 
+        /* statistics */
+        uint32 GetNumInstances();
+        uint32 GetNumPlayersInInstances();
+
     private:
         // debugging code, should be deleted some day
         void checkAndCorrectGridStatesArray();              // just for debugging to find some memory overwrites
Index: src/game/Chat.cpp
===================================================================
--- src/game/Chat.cpp	(revision 5727)
+++ src/game/Chat.cpp	(working copy)
@@ -389,6 +389,7 @@
         { "cometome",       SEC_ADMINISTRATOR,  &ChatHandler::HandleComeToMeCommand,            "", NULL },
 
         //! Development Commands
+        { "instance",       SEC_ADMINISTRATOR,  &ChatHandler::HandleInstanceCommand,            "", NULL },
         { "setvalue",       SEC_ADMINISTRATOR,  &ChatHandler::HandleSetValue,                   "", NULL },
         { "getvalue",       SEC_ADMINISTRATOR,  &ChatHandler::HandleGetValue,                   "", NULL },
         { "Mod32Value",     SEC_ADMINISTRATOR,  &ChatHandler::HandleMod32Value,                 "", NULL },
Index: src/game/Group.h
===================================================================
--- src/game/Group.h	(revision 5727)
+++ src/game/Group.h	(working copy)
@@ -90,6 +90,8 @@
                                                                 // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19
 static const uint8 GroupUpdateLength[GROUP_UPDATE_FLAGS_COUNT] = { 0, 2, 2, 2, 1, 2, 2, 2, 2, 4, 8, 8, 1, 2, 2, 2, 1, 2, 2, 8};
 
+class InstanceSave;
+
 class Roll : public LootValidatorRef
 {
     public:
@@ -112,6 +114,15 @@
         uint8 itemSlot;
 };
 
+struct InstanceGroupBind
+{
+    InstanceSave *save;
+    bool perm;
+    /* permanent InstanceGroupBinds exist iff the leader has a permanent
+       PlayerInstanceBind for the same instance. */
+    InstanceGroupBind() : save(NULL), perm(false) {}
+};
+
 /** request member stats checken **/
 /** todo: uninvite people that not accepted invite **/
 class MANGOS_DLL_SPEC Group
@@ -126,6 +137,8 @@
         };
         typedef std::list<MemberSlot> MemberSlotList;
         typedef MemberSlotList::const_iterator member_citerator;
+
+        typedef HM_NAMESPACE::hash_map< uint32 /*mapId*/, InstanceGroupBind> BoundInstancesMap;
     protected:
         typedef MemberSlotList::iterator member_witerator;
         typedef std::set<uint64> InvitesList;
@@ -138,7 +151,8 @@
 
         // group manipulation methods
         bool   Create(const uint64 &guid, const char * name);
-        bool   LoadGroupFromDB(const uint64 &leaderGuid);
+        bool   LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result = NULL, bool loadMembers = true);
+        bool   LoadMemberFromDB(uint32 guidLow, uint8 subgroup, bool assistant);
         bool   AddInvite(Player *player);
         uint32 RemoveInvite(Player *player);
         bool   AddMember(const uint64 &guid, const char* name);
@@ -242,6 +256,11 @@
         }
 
         void SetTargetIcon(uint8 id, uint64 guid);
+        void SetDifficulty(uint8 difficulty);
+        uint8 GetDifficulty() { return m_difficulty; }
+        uint16 InInstance();
+        bool InCombatToInstance(uint32 instanceId);
+        void ResetInstances(uint8 method, Player* SendMsgTo);
 
         // -no description-
         //void SendInit(WorldSession *session);
@@ -281,6 +300,10 @@
         void LinkMember(GroupReference *pRef) { m_memberMgr.insertFirst(pRef); }
         void DelinkMember(GroupReference* /*pRef*/ ) { }
 
+        InstanceGroupBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false);
+        void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false);
+        InstanceGroupBind* GetBoundInstance(uint32 mapid, uint8 difficulty);
+
     protected:
         bool _addMember(const uint64 &guid, const char* name, bool isAssistant=false);
         bool _addMember(const uint64 &guid, const char* name, bool isAssistant, uint8 group);
@@ -295,6 +318,8 @@
         bool _setMainTank(const uint64 &guid);
         bool _setMainAssistant(const uint64 &guid);
 
+        void _homebindIfInstance(Player *player);
+
         member_citerator _getMemberCSlot(uint64 Guid) const
         {
             for(member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
@@ -323,11 +348,14 @@
         uint64              m_mainTank;
         uint64              m_mainAssistant;
         GroupType           m_groupType;
+        uint8               m_difficulty;
         BattleGround*       m_bgGroup;
         uint64              m_targetIcons[TARGETICONCOUNT];
         LootMethod          m_lootMethod;
         ItemQualities       m_lootThreshold;
         uint64              m_looterGuid;
         Rolls               RollId;
+        // does not include permanent binds or solo binds
+        BoundInstancesMap   m_boundInstances[TOTAL_DIFFICULTIES];
 };
 #endif
Index: src/game/Player.h
===================================================================
--- src/game/Player.h	(revision 5727)
+++ src/game/Player.h	(working copy)
@@ -463,12 +463,6 @@
     ERR_TAXINOTSTANDING             = 12
 };
 
-enum DungeonDifficulties
-{
-    DUNGEONDIFFICULTY_NORMAL = 0,
-    DUNGEONDIFFICULTY_HEROIC = 1
-};
-
 enum LootType
 {
     LOOT_CORPSE                 = 1,
@@ -782,9 +776,8 @@
 MovementFlags const movementOrTurningFlagsMask = MovementFlags(
     movementFlagsMask | MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT
 );
+class InstanceSave;
 
-typedef HM_NAMESPACE::hash_map< uint32, std::pair < uint32, uint32 > > BoundInstancesMap;
-
 enum RestType
 {
     REST_TYPE_NO        = 0,
@@ -839,6 +832,16 @@
 #define MAX_PLAYER_SUMMON_DELAY                   (2*MINUTE)
 #define MAX_MONEY_AMOUNT                       (0x7FFFFFFF-1)
 
+struct InstancePlayerBind
+{
+    InstanceSave *save;
+    bool perm;
+    /* permanent PlayerInstanceBinds are created in Raid/Heroic instances for players
+       that aren't already permanently bound when they are inside when a boss is killed
+       or when they enter an instance that the group leader is permanently bound to. */
+    InstancePlayerBind() : save(NULL), perm(false) {}
+};
+
 class MANGOS_DLL_SPEC PlayerTaxi
 {
     public:
@@ -930,7 +933,7 @@
         void SendInitialPacketsBeforeAddToMap();
         void SendInitialPacketsAfterAddToMap();
         void SendTransferAborted(uint32 mapid, uint16 reason);
-        void SendRaidInstanceResetWarning(uint32 type, uint32 mapid, uint32 time);
+        void SendInstanceResetWarning(uint32 mapid, uint32 time);
 
         bool CanInteractWithNPCs(bool alive = true) const;
 
@@ -1487,8 +1490,8 @@
         void SetArenaTeamIdInvited(uint32 ArenaTeamId) { m_ArenaTeamIdInvited = ArenaTeamId; }
         uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; }
 
-        void SetDungeonDifficulty(uint32 difficulty) { m_dungeonDifficulty = difficulty; }
-        uint32 GetDungeonDifficulty() { return m_dungeonDifficulty; }
+        void SetDifficulty(uint32 dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; }
+        uint8 GetDifficulty() { return m_dungeonDifficulty; }
 
         bool UpdateSkill(uint32 skill_id);
 
@@ -1567,7 +1570,11 @@
         void SendAutoRepeatCancel();
         void SendExplorationExperience(uint32 Area, uint32 Experience);
 
-        void SendDungeonDifficulty();
+        void SendDungeonDifficulty(bool IsInGroup);
+        void ResetInstances(uint8 method);
+        void SendResetInstanceSuccess(uint32 MapId);
+        void SendResetInstanceFailed(uint32 reason, uint32 MapId);
+        void SendResetFailedNotify(uint32 mapid);
 
         bool SetPosition(float x, float y, float z, float orientation, bool teleport = false);
         void SendMessageToSet(WorldPacket *data, bool self);// overwrite Object::SendMessageToSet
@@ -1914,12 +1921,23 @@
         /***                 INSTANCE SYSTEM                   ***/
         /*********************************************************/
 
+        typedef HM_NAMESPACE::hash_map< uint32 /*mapId*/, InstancePlayerBind > BoundInstancesMap;
+
         void UpdateHomebindTime(uint32 time);
 
         bool m_Loaded;
         uint32 m_HomebindTimer;
         bool m_InstanceValid;
-        BoundInstancesMap m_BoundInstances;
+        // permanent binds and solo binds by difficulty
+        BoundInstancesMap m_boundInstances[TOTAL_DIFFICULTIES];
+        InstancePlayerBind* GetBoundInstance(uint32 mapid, uint8 difficulty);
+        BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; }
+        void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false);
+        void UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload = false);
+        InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false);
+        void SendRaidInfo();
+        void SendSavedInstances();
+        void ConvertInstancesToGroup(bool load = false);
 
         /*********************************************************/
         /***                   GROUP SYSTEM                    ***/
@@ -1998,7 +2016,6 @@
 
         void _SaveActions();
         void _SaveAuras();
-        void _SaveBoundInstances();
         void _SaveInventory();
         void _SaveMail();
         void _SaveQuestStatus();
Index: src/game/Map.h
===================================================================
--- src/game/Map.h	(revision 5727)
+++ src/game/Map.h	(working copy)
@@ -38,6 +38,7 @@
 class Unit;
 class WorldPacket;
 class InstanceData;
+class Group;
 
 namespace ZThread
 {
@@ -103,6 +104,11 @@
     char const* script;
 };
 
+enum LevelRequirementVsMode
+{
+    LEVELREQUIREMENT_HEROIC = 70
+};
+
 #if defined( __GNUC__ )
 #pragma pack()
 #else
@@ -113,26 +119,24 @@
 
 #define MAX_HEIGHT            100000.0f                     // can be use for find ground height at surface
 #define INVALID_HEIGHT       -100000.0f                     // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE
+class InstanceSave;
 
 class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::ObjectLevelLockable<Map, ZThread::Mutex>
 {
     public:
-        typedef std::list<Player*> PlayerList;
-
-        Map(uint32 id, time_t, uint32 aInstanceId);
+        Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode);
         virtual ~Map();
 
-        void Add(Player *);
-        bool AddInstanced(Player *);
-        void Remove(Player *, bool);
-        void RemoveInstanced(Player *);
+        // currently unused for normal maps
+        virtual bool CanUnload(const uint32& diff) { return false; }
+
+        virtual bool Add(Player *);
+        virtual void Remove(Player *, bool);
         template<class T> void Add(T *);
         template<class T> void Remove(T *, bool);
 
         virtual void Update(const uint32&);
 
-        std::list<Player*>& GetPlayers() { return i_Players;}
-
         void MessageBroadcast(Player *, WorldPacket *, bool to_self, bool own_team_only = false);
 
         void MessageBroadcast(WorldObject *, WorldPacket *);
@@ -200,20 +204,19 @@
         // assert print helper
         bool CheckGridIntegrity(Creature* c, bool moved) const;
 
-        std::string GetScript() { return i_script; }
-        InstanceData* GetInstanceData() { return i_data; }
         uint32 GetInstanceId() { return i_InstanceId; }
-        bool NeedsReset() { return Instanceable() && ( i_resetTime == 0 || i_resetTime <= time(NULL)); }
-        uint32 GetPlayersCountExceptGMs() const;
-        uint32 HavePlayers() const { return !i_Players.empty(); }
-        void Reset();
-        bool CanEnter(Player* player) const;
+        uint8 GetSpawnMode() { return (i_spawnMode); }
+        virtual bool CanEnter(Player* player) { return true; }
         const char* GetMapName() const;
 
         bool Instanceable() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID))); }
         // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable
         bool IsDungeon() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID))); }
         bool IsRaid() const { return(i_mapEntry && (i_mapEntry->map_type == MAP_RAID)); }
+        bool IsHeroic() const { return i_spawnMode == DIFFICULTY_HEROIC; }
+        bool IsBattleArena() const { return(i_mapEntry && (i_mapEntry->map_type == MAP_ARENA)); }
+        bool IsBattleGround() const { return(i_mapEntry && (i_mapEntry->map_type == MAP_BATTLEGROUND)); }
+        bool IsBattleGroundOrArena() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_BATTLEGROUND) || (i_mapEntry->map_type == MAP_ARENA))); }
         bool IsMountAllowed() const
         {
             return !IsDungeon() || i_mapEntry && (
@@ -222,7 +225,6 @@
         }
 
         virtual bool RemoveBones(uint64 guid, float x, float y);
-        void InitResetTime();
 
         void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair);
         void UpdatePlayerVisibility(Player* player, Cell cell, CellPair cellpair);
@@ -272,27 +274,21 @@
     protected:
         typedef MaNGOS::ObjectLevelLockable<Map, ZThread::Mutex>::Lock Guard;
 
+        MapEntry const* i_mapEntry;
+        uint8 i_spawnMode;
+        uint32 i_id;
+        uint32 i_InstanceId;
+
     private:
         typedef GridReadGuard ReadGuard;
         typedef GridWriteGuard WriteGuard;
 
-        uint32 i_id;
         NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
         GridMap *GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
         std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP*TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells;
 
         time_t i_gridExpiry;
 
-        MapEntry const* i_mapEntry;
-        time_t i_resetTime;
-        uint32 i_resetDelayTime;
-        uint32 i_InstanceId;
-        uint32 i_maxPlayers;
-        InstanceData* i_data;
-        std::string i_script;
-
-        PlayerList i_Players;
-
         // Type specific code for add/remove to/from grid
         template<class T>
             void AddToGrid(T*, NGridType *, Cell const&);
@@ -307,6 +303,51 @@
             void DeleteFromWorld(T*);
 };
 
+enum InstanceResetMethod
+{
+    INSTANCE_RESET_ALL,
+    INSTANCE_RESET_CHANGE_DIFFICULTY,
+    INSTANCE_RESET_GLOBAL,
+    INSTANCE_RESET_GROUP_DISBAND,
+    INSTANCE_RESET_GROUP_JOIN,
+    INSTANCE_RESET_RESPAWN_DELAY
+};
+
+class InstanceMap : public Map
+{
+    public:
+        typedef std::list<Player *> PlayerList;                 // online players only
+
+        InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode);
+        ~InstanceMap();
+        bool Add(Player *);
+        void Remove(Player *, bool);
+        void Update(const uint32&);
+        void CreateInstanceData(bool load);
+        bool Reset(uint8 method);
+        std::string GetScript() { return i_script; }
+        InstanceData* GetInstanceData() { return i_data; }
+        void PermBindAllPlayers();
+        PlayerList& GetPlayerList() { return i_Players; }
+        time_t GetResetTime();
+        bool CanUnload(const uint32& diff);
+        void UnloadAll(bool pForce);
+        bool CanEnter(Player* player);
+        uint32 GetPlayersCountExceptGMs() const;
+        uint32 HavePlayers() const { return !i_Players.empty(); }
+        void SendResetWarnings(uint32 timeLeft);
+        void SetResetSchedule(bool on);
+    private:
+        uint32 m_unloadTimer;
+        bool m_resetAfterUnload;
+        bool m_unloadWhenEmpty;
+        InstanceData* i_data;
+        std::string i_script;
+        // only online players that are inside the instance currently
+        // TODO ? - use the grid instead to access the players
+        PlayerList i_Players;
+};
+
 /*inline
 uint64
 Map::CalculateGridMask(const uint32 &y) const
Index: src/game/Pet.h
===================================================================
--- src/game/Pet.h	(revision 5727)
+++ src/game/Pet.h	(working copy)
@@ -216,7 +216,7 @@
         int32   m_bonusdamage;
         uint64  m_auraUpdateMask;
     private:
-        void SaveToDB()                                     // overwrited of Creature::SaveToDB     - don't must be called
+        void SaveToDB(uint32, uint8)                        // overwrited of Creature::SaveToDB     - don't must be called
         {
             assert(false);
         }
Index: src/game/Opcodes.h
===================================================================
--- src/game/Opcodes.h	(revision 5727)
+++ src/game/Opcodes.h	(working copy)
@@ -828,7 +828,7 @@
     CMSG_RESET_INSTANCES                            = 797,  // reset instances, empty
     SMSG_RESET_INSTANCES_SUCCESS                    = 798,  // uint32 mapid, chat message: %s has been reset.
     SMSG_RESET_INSTANCES_FAILED                     = 799,  // uint32 reason, uint32 mapid
-    SMSG_UNKNOWN_800                                = 800,  // uint32 mapid, instance related (save?)
+    SMSG_INSTANCE_SAVE                              = 800,  // uint32 mapid, nstance save from player
     MSG_RAID_ICON_TARGET                            = 801,  // uint8+uint8+uint64 guid or only uint8(0x01)
     MSG_RAID_READY_CHECK                            = 802,  // uint64(server) or empty(client)
     // 803 not exist?
@@ -839,7 +839,7 @@
     SMSG_GM_SURVEY_REQUEST                          = 808,  // uint32, 1 - causes client get ticket request, 2 - hide, 3 - show
     MSG_SET_DUNGEON_DIFFICULTY                      = 809,  // uint32+uint32+uint32
     CMSG_GM_SURVEY_RESULTS                          = 810,  // script function named GMSurveySubmit()
-    SMSG_UNKNOWN_811                                = 811,  // uint32, 0x0, SMSG_INSTANCE_RESET_ACTIVATE ?
+    SMSG_INSTANCE_RESET_ACTIVATE                    = 811,  // instance can reset
     SMSG_UNKNOWN_812                                = 812,
     SMSG_UNKNOWN_813                                = 813,  // string
     // 814 not exist?
Index: src/game/BattleGroundWS.h
===================================================================
--- src/game/BattleGroundWS.h	(revision 5727)
+++ src/game/BattleGroundWS.h	(working copy)
@@ -140,6 +140,7 @@
         void EventPlayerCapturedFlag(Player *Source);
         void EventPlayerDroppedFlag(Player *Source);
         void EventPlayerReturnedFlag(Player *Source);
+        void EventDropTimerReturnedFlag(uint32 Team);
         void EventPlayerPickedUpFlag(Player *Source);
 
         void RemovePlayer(Player *plr, uint64 guid);
Index: src/game/Makefile.am
===================================================================
--- src/game/Makefile.am	(revision 5727)
+++ src/game/Makefile.am	(working copy)
@@ -144,6 +144,8 @@
 	Mail.h \
 	Map.cpp \
 	Map.h \
+	MapInstancedSaveMgr.cpp \
+	MapInstancedSaveMgr.h \
 	MapInstanced.cpp \
 	MapInstanced.h \
 	MapManager.cpp \
Index: src/game/MiscHandler.cpp
===================================================================
--- src/game/MiscHandler.cpp	(revision 5727)
+++ src/game/MiscHandler.cpp	(working copy)
@@ -929,36 +929,115 @@
 
     // NULL if all values default (non teleport trigger)
     AreaTrigger const* at = objmgr.GetAreaTrigger(Trigger_ID);
+    if(!at) return;
 
-    if(at)
+    if(!GetPlayer()->isGameMaster())
     {
-        if(at->requiredItem)
+        uint32 missingLevel = 0;
+        if(GetPlayer()->getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL))
+            missingLevel = at->requiredLevel;
+
+        // must have one or the other, report the first one that's missing
+        uint32 missingItem = 0;
+        if(at->requiredItem && !GetPlayer()->HasItemCount(at->requiredItem, 1))
+            missingItem = at->requiredItem;
+        else if(at->requiredItem2 && !GetPlayer()->HasItemCount(at->requiredItem2, 1))
+            missingItem = at->requiredItem2;
+
+        uint32 missingKey = 0;
+        if(at->heroicKey && !GetPlayer()->HasItemCount(at->heroicKey, 1))
+            missingKey = at->heroicKey;
+        else if(at->heroicKey2 && !GetPlayer()->HasItemCount(at->heroicKey2, 1))
+            missingKey = at->heroicKey2;
+
+        uint32 missingQuest = 0;
+        if(at->requiredQuest && !GetPlayer()->GetQuestRewardStatus(at->requiredQuest))
+            missingQuest = at->requiredQuest;
+
+        if(missingLevel || missingItem || missingKey || missingQuest)
         {
-            uint32 ReqItem = at->requiredItem;
+            // TODO: all this is probably wrong
+            if(missingItem)
+                SendAreaTriggerMessage(objmgr.GetMangosString(LANG_LEVEL_MINREQUIRED_AND_ITEM,GetSessionLocaleIndex()), at->requiredLevel, objmgr.GetItemPrototype(missingItem)->Name1);
+            else if(missingKey)
+                GetPlayer()->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY2);
+            else if(missingQuest)
+                SendAreaTriggerMessage(at->requiredFailedText.c_str());
+            else if(missingLevel)
+                SendAreaTriggerMessage(objmgr.GetMangosString(LANG_LEVEL_MINREQUIRED,GetSessionLocaleIndex()), missingLevel);
+            return;
+        }
+    }
+    
+    GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,true,false);
+
+        /*bool required = false;
+        if(at->requiredItem || at->requiredItem2)
+        {
+            required = true;
+            uint32 ReqItem = 0;
+            if(at->requiredItem)
+                ReqItem = at->requiredItem;
+            else
+                ReqItem = at->requiredItem2;
             ItemPrototype const *pProto = objmgr.GetItemPrototype(ReqItem);
             // pProto != NULL checked and fixed (if need with error output) at server load and don't must be happens here
 
             // item and level or GM
-            if( (!pProto || GetPlayer()->HasItemCount(ReqItem, 1)) &&
+            if( (GetPlayer()->HasItemCount(at->requiredItem, 1) || GetPlayer()->HasItemCount(at->requiredItem2, 1)) &&
                 (GetPlayer()->getLevel() >= at->requiredLevel || sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL))
                 || GetPlayer()->isGameMaster() )
                 GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,true,false);
             else
             {
+                // TODO!!!
                 std::stringstream msgstr;
+                if(at->requiredFailedText.c_str() != NULL)
+                    msgstr << at->requiredFailedText.c_str();
+                else
+                    msgstr << LANG_LEVEL_MINREQUIRED << (uint32)at->requiredLevel << " and have " << pProto->Name1 << LANG_LEVEL_MINREQUIRED_END;
+                std::string msg = msgstr.str();
                 SendAreaTriggerMessage(objmgr.GetMangosString(LANG_LEVEL_MINREQUIRED_AND_ITEM,GetSessionLocaleIndex()),(uint32)at->requiredLevel,pProto->Name1);
             }
         }
-        else
+        if((at->heroicKey || at->heroicKey2) && GetPlayer()->GetDifficulty() == DIFFICULTY_HEROIC)
         {
-            if(GetPlayer()->getLevel() >= at->requiredLevel || sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL) || GetPlayer()->isGameMaster())
+            required = true;
+            uint32 HeroicKey = 0;
+            if(at->heroicKey)
+                HeroicKey = at->heroicKey;
+            else
+                HeroicKey = at->heroicKey2;
+
+            ItemPrototype const *pProto = objmgr.GetItemPrototype(HeroicKey);
+
+            if( (GetPlayer()->HasItemCount(at->heroicKey, 1) || GetPlayer()->HasItemCount(at->heroicKey2, 1)) && 
+                (GetPlayer()->getLevel() >= at->requiredLevel || sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL)) 
+                || GetPlayer()->isGameMaster() )
                 GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,true,false);
             else
+                GetPlayer()->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY2);
+        }
+        if(at->requiredQuest)
+        {
+            required = true;
+            uint32 ReqQuest = at->requiredQuest;
+            if((GetPlayer()->GetQuestRewardStatus(ReqQuest) && GetPlayer()->getLevel() >= at->requiredLevel)|| sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL) || GetPlayer()->isGameMaster())
+                GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,true,false);
+            else
             {
+                std::stringstream msgstr;
+                msgstr << at->requiredFailedText.c_str();
+                std::string msg = msgstr.str();
                 SendAreaTriggerMessage(objmgr.GetMangosString(LANG_LEVEL_MINREQUIRED,GetSessionLocaleIndex()),(uint32)at->requiredLevel );
             }
         }
-    }
+        if(required)
+            return;
+        if(GetPlayer()->getLevel() >= at->requiredLevel || sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL) || GetPlayer()->isGameMaster())
+            GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,true,false);
+        else
+            SendAreaTriggerMessage(objmgr.GetMangosString(LANG_LEVEL_MINREQUIRED,GetSessionLocaleIndex()),(uint32)at->requiredLevel );*/
 }
 
 void WorldSession::HandleUpdateAccountData(WorldPacket &/*recv_data*/)
@@ -1507,12 +1586,14 @@
 void WorldSession::HandleResetInstancesOpcode( WorldPacket & /*recv_data*/ )
 {
     sLog.outDebug("WORLD: CMSG_RESET_INSTANCES");
-    /*
-        uint32 mapid = 0;
-        WorldPacket data(SMSG_RESET_INSTANCES_SUCCESS, 4);
-        data << mapid;
-        _player->GetSession()->SendPacket(&data);
-    */
+    Group *pGroup = _player->GetGroup();
+    if(pGroup)
+    {
+        if(pGroup->IsLeader(_player->GetGUID()))
+            pGroup->ResetInstances(INSTANCE_RESET_ALL, _player);
+    }
+    else
+        _player->ResetInstances(INSTANCE_RESET_ALL);
 }
 
 void WorldSession::HandleDungeonDifficultyOpcode( WorldPacket & recv_data )
@@ -1521,11 +1602,44 @@
 
     sLog.outDebug("MSG_SET_DUNGEON_DIFFICULTY");
 
-    uint32 difficulty;
-    recv_data >> difficulty;
+    uint32 mode;
+    recv_data >> mode;
 
-    GetPlayer()->SetDungeonDifficulty(difficulty);
-    GetPlayer()->SendDungeonDifficulty();
+    if(mode == _player->GetDifficulty())
+        return;
+    
+    if(mode > DIFFICULTY_HEROIC)
+    {
+        sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode);
+        return;
+    }
+
+    // cannot reset while in an instance
+    Map *map = _player->GetMap();
+    if(map && map->IsDungeon())
+    {
+        sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow());
+        return;
+    }
+
+    if(_player->getLevel() < LEVELREQUIREMENT_HEROIC)
+        return;
+    Group *pGroup = _player->GetGroup();
+    if(pGroup)
+    {
+        if(pGroup->IsLeader(_player->GetGUID()))
+        {
+            // the difficulty is set even if the instances can't be reset
+            //_player->SendDungeonDifficulty(true);
+            pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player);
+            pGroup->SetDifficulty(mode);
+        }
+    }
+    else
+    {
+        _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY);
+        _player->SetDifficulty(mode);
+    }
 }
 
 void WorldSession::HandleNewUnknownOpcode( WorldPacket & recv_data )
Index: src/game/GroupHandler.cpp
===================================================================
--- src/game/GroupHandler.cpp	(revision 5727)
+++ src/game/GroupHandler.cpp	(working copy)
@@ -27,6 +27,7 @@
 #include "Player.h"
 #include "Group.h"
 #include "ObjectAccessor.h"
+#include "MapManager.h"
 #include "SocialMgr.h"
 
 /* differeces from off:
@@ -86,8 +87,18 @@
         SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_TARGET_UNFRIENDLY);
         return;
     }
+    if(GetPlayer()->GetInstanceId() != 0 && player->GetInstanceId() != 0 && GetPlayer()->GetInstanceId() != player->GetInstanceId() && GetPlayer()->GetMapId() == player->GetMapId())
+    {
+        SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_NOT_IN_YOUR_INSTANCE);
+        return;
+    }
+    // just ignore us
+    if(player->GetInstanceId() != 0 && player->GetDifficulty() != GetPlayer()->GetDifficulty())
+    {
+        SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_TARGET_IGNORE_YOU);
+        return;
+    }
 
-    // just ignore us
     if(player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
     {
         SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_TARGET_IGNORE_YOU);
@@ -184,6 +195,13 @@
         return;
     }
 
+    // if the leader has solo saves, convert them to group saves
+    if(group->GetMembersCount() == 1) leader->ConvertInstancesToGroup();
+    
+    // reset the acceptee's solo instances, unless he is currently in one of them
+    // including raid/heroic instances that they are not permanently bound to!
+    GetPlayer()->ResetInstances(INSTANCE_RESET_GROUP_JOIN);
+
     // everything's fine, do it
     if(!group->AddMember(GetPlayer()->GetGUID(), GetPlayer()->GetName()))
         return;
@@ -279,6 +297,11 @@
     }
 
     Player *player = objmgr.GetPlayer(guid);
+    if(!player)
+    {
+        sLog.outError("HandleGroupUninvite - error");
+        return;
+    }
 
     /** error handling **/
     if(!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
@@ -323,7 +346,7 @@
     group->ChangeLeader(guid);
 }
 
-void WorldSession::HandleGroupDisbandOpcode( WorldPacket & /*recv_data*/ )
+void WorldSession::HandleGroupLeaveOpcode( WorldPacket & /*recv_data*/ )
 {
     if(!GetPlayer()->GetGroup())
         return;
@@ -857,21 +880,8 @@
 
 /*!*/void WorldSession::HandleRequestRaidInfoOpcode( WorldPacket & /*recv_data*/ )
 {
-    //sLog.outDebug("Received opcode CMSG_REQUEST_RAID_INFO");
-
-    WorldPacket data(SMSG_RAID_INSTANCE_INFO, 4);
-    data << (uint32)0;                                      // count (max is 10)
-
-    /*data << (uint32)count;
-    for(int i=0; i<count; i++)
-    {
-        data << (uint32)mapid;
-        data << (uint32)time_left_in_seconds; // time to reset
-        data << (uint32)instanceid;
-        data << (uint32)0;      // unknown
-    }*/
-
-    GetPlayer()->GetSession()->SendPacket(&data);
+    // every time the player checks the character screen
+    _player->SendRaidInfo();
 }
 
 /*void WorldSession::HandleGroupCancelOpcode( WorldPacket & recv_data )
Index: src/game/World.h
===================================================================
--- src/game/World.h	(revision 5727)
+++ src/game/World.h	(working copy)
@@ -85,7 +85,10 @@
     CONFIG_INSTANCE_IGNORE_LEVEL,
     CONFIG_INSTANCE_IGNORE_RAID,
     CONFIG_BATTLEGROUND_CAST_DESERTER,
+    CONFIG_INSTANCE_RESET_TIME_HOUR,
+    CONFIG_INSTANCE_UNLOAD_DELAY,
     CONFIG_CAST_UNSTUCK,
+
     CONFIG_MAX_PRIMARY_TRADE_SKILL,
     CONFIG_MIN_PETITION_SIGNS,
     CONFIG_GM_WISPERING_TO,
@@ -166,6 +169,7 @@
     RATE_MINING_NEXT,
     RATE_TALENT,
     RATE_LOYALTY,
+    RATE_INSTANCE_RESET_TIME,
     MAX_RATES
 };
 
Index: src/game/debugcmds.cpp
===================================================================
--- src/game/debugcmds.cpp	(revision 5727)
+++ src/game/debugcmds.cpp	(working copy)
@@ -29,6 +29,8 @@
 #include "ObjectAccessor.h"
 #include "GossipDef.h"
 #include "Language.h"
+#include "MapManager.h"
+#include "MapInstancedSaveMgr.h"
 
 bool ChatHandler::HandleDebugInArcCommand(const char* /*args*/)
 {
@@ -507,3 +509,61 @@
 
     return true;
 }
+
+std::string GetTimeString(uint32 time)
+{
+    uint16 days = time / DAY, hours = (time % DAY) / HOUR, minute = (time % HOUR) / MINUTE;
+    std::ostringstream ss;
+    if(days) ss << days << "d ";
+    if(hours) ss << hours << "h ";
+    ss << minute << "m";
+    return ss.str();
+}
+
+bool ChatHandler::HandleInstanceCommand(const char* args)
+{
+    if(!args)
+        return true;
+
+    std::string cmd = args;
+    if(cmd == "stats")
+    {
+        PSendSysMessage("instances loaded: %d", MapManager::Instance().GetNumInstances());
+        PSendSysMessage("players in instances: %d", MapManager::Instance().GetNumPlayersInInstances());
+        PSendSysMessage("instance saves: %d", sInstanceSaveManager.GetNumInstanceSaves());
+        PSendSysMessage("players bound: %d", sInstanceSaveManager.GetNumBoundPlayersTotal());
+        PSendSysMessage("groups bound: %d", sInstanceSaveManager.GetNumBoundGroupsTotal());
+    }
+    else if(cmd == "unbindall")
+    {
+        Player* player = getSelectedPlayer();
+        if (!player) player = m_session->GetPlayer();
+        for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
+        {
+            Player::BoundInstancesMap &binds = player->GetBoundInstances(i);
+            for(Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();)
+            {
+                if(itr->first != player->GetMapId())
+                    player->UnbindInstance(itr, i);
+                else
+                    ++itr;
+            }
+        }
+    }
+    else if(cmd == "listbinds")
+    {
+        Player* player = getSelectedPlayer();
+        if (!player) player = m_session->GetPlayer();
+        for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
+        {
+            Player::BoundInstancesMap &binds = player->GetBoundInstances(i);
+            for(Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end(); ++itr)
+            {
+                InstanceSave *save = itr->second.save;
+                std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL));
+                PSendSysMessage("map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no",  save->GetDifficulty() == DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str());
+            }
+        }
+    }
+    return true;
+}
Index: src/game/GameObject.cpp
===================================================================
--- src/game/GameObject.cpp	(revision 5727)
+++ src/game/GameObject.cpp	(working copy)
@@ -147,9 +147,9 @@
     //Only works if you create the object in it, not if it is moves to that map.
     //Normally non-players do not teleport to other maps.
     Map *map = MapManager::Instance().GetMap(GetMapId(), this);
-    if(map && map->GetInstanceData())
+    if(map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
     {
-        map->GetInstanceData()->OnObjectCreate(this);
+        ((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this);
     }
 
     return true;
@@ -455,6 +455,20 @@
 
 void GameObject::SaveToDB()
 {
+    // this should only be used when the creature has already been loaded
+    // perferably after adding to map, because mapid may not be valid otherwise
+    GameObjectData const *data = objmgr.GetGOData(m_DBTableGuid);
+    if(!data)
+    {
+        sLog.outError("GameObject::SaveToDB failed, cannot get gameobject data!");
+        return;
+    }
+
+    SaveToDB(GetMapId(), data->spawnMask);
+}
+
+void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask)
+{
     const GameObjectInfo *goI = GetGOInfo();
 
     if (!goI)
@@ -465,7 +479,7 @@
 
     // data->guid = guid don't must be update at save
     data.id = GetEntry();
-    data.mapid = GetMapId();
+    data.mapid = mapid;
     data.posX = GetFloatValue(GAMEOBJECT_POS_X);
     data.posY = GetFloatValue(GAMEOBJECT_POS_Y);
     data.posZ = GetFloatValue(GAMEOBJECT_POS_Z);
@@ -477,13 +491,15 @@
     data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime;
     data.animprogress = GetUInt32Value (GAMEOBJECT_ANIMPROGRESS);
     data.go_state = GetUInt32Value (GAMEOBJECT_STATE);
+    data.spawnMask = spawnMask;
 
     // updated in DB
     std::ostringstream ss;
     ss << "INSERT INTO gameobject VALUES ( "
         << m_DBTableGuid << ", "
         << GetUInt32Value (OBJECT_FIELD_ENTRY) << ", "
-        << GetMapId() << ", "
+        << mapid << ", "
+        << (uint32)spawnMask << ", "
         << GetFloatValue(GAMEOBJECT_POS_X) << ", "
         << GetFloatValue(GAMEOBJECT_POS_Y) << ", "
         << GetFloatValue(GAMEOBJECT_POS_Z) << ", "
Index: src/game/WorldSession.h
===================================================================
--- src/game/WorldSession.h	(revision 5727)
+++ src/game/WorldSession.h	(working copy)
@@ -311,7 +311,7 @@
         void HandleGroupUninviteGuidOpcode(WorldPacket& recvPacket);
         void HandleGroupUninvite(uint64 guid, std::string name);
         void HandleGroupSetLeaderOpcode(WorldPacket& recvPacket);
-        void HandleGroupDisbandOpcode(WorldPacket& recvPacket);
+        void HandleGroupLeaveOpcode(WorldPacket& recvPacket);
         void HandleGroupPassOnLootOpcode( WorldPacket &recv_data );
         void HandleLootMethodOpcode(WorldPacket& recvPacket);
         void HandleLootRoll( WorldPacket &recv_data );
Index: src/game/MapManager.cpp
===================================================================
--- src/game/MapManager.cpp	(revision 5727)
+++ src/game/MapManager.cpp	(working copy)
@@ -17,6 +17,7 @@
  */
 
 #include "MapManager.h"
+#include "MapInstancedSaveMgr.h"
 #include "Policies/SingletonImp.h"
 #include "Database/DatabaseEnv.h"
 #include "Log.h"
@@ -27,6 +28,8 @@
 #include "DestinationHolderImp.h"
 #include "World.h"
 #include "CellImpl.h"
+#include "Corpse.h"
+#include "ObjectMgr.h"
 
 #define CLASS_LOCK MaNGOS::ClassLevelLockable<MapManager, ZThread::Mutex>
 INSTANTIATE_SINGLETON_2(MapManager, CLASS_LOCK);
@@ -104,13 +107,13 @@
         Guard guard(*this);
 
         const MapEntry* entry = sMapStore.LookupEntry(id);
-        if (entry && ((entry->map_type == MAP_INSTANCE) || (entry->map_type == MAP_RAID)))
+        if (entry && entry->IsDungeon())
         {
             m = new MapInstanced(id, i_gridCleanUpDelay, 0);
         }
         else
         {
-            m = new Map(id, i_gridCleanUpDelay, 0);
+            m = new Map(id, i_gridCleanUpDelay, 0, 0);
         }
         i_maps[id] = m;
     }
@@ -128,11 +131,93 @@
     return m;
 }
 
+/*
+    checks that do not require a map to be created
+    will send transfer error messages on fail
+*/
 bool MapManager::CanPlayerEnter(uint32 mapid, Player* player)
 {
-    return GetBaseMap(mapid)->CanEnter(player);
+    const MapEntry *entry = sMapStore.LookupEntry(mapid);
+    if(!entry) return false;
+    const char *mapName = entry->name[sWorld.GetDBClang()];
+    
+    if(entry->map_type == MAP_INSTANCE || entry->map_type == MAP_RAID)
+    {
+        if (entry->map_type == MAP_RAID)
+        {
+            // GMs can avoid raid limitations
+            if(!player->isGameMaster() && !sWorld.getConfig(CONFIG_INSTANCE_IGNORE_RAID))
+            {
+                // can only enter in a raid group
+                Group* group = player->GetGroup();
+                if (!group || !group->isRaidGroup())
+                {
+                    // probably there must be special opcode, because client has this string constant in GlobalStrings.lua
+                    // TODO: this is not a good place to send the message
+                    player->GetSession()->SendAreaTriggerMessage("You must be in a raid group to enter %s instance", mapName);
+                    sLog.outDebug("MAP: Player '%s' must be in a raid group to enter instance of '%s'", player->GetName(), mapName);
+                    return false;
+                }
+            }
+        }
+
+        //The player has a heroic mode and tries to enter into instance which has no a heroic mode
+        if (!entry->SupportsHeroicMode() && player->GetDifficulty() == DIFFICULTY_HEROIC)  
+        {
+            player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY2);      //Send aborted message
+            return false;
+        }
+
+        if (!player->isAlive())
+        {
+            if(Corpse *corpse = player->GetCorpse())
+            {
+                // let enter in ghost mode in instance that connected to inner instance with corpse
+                uint32 instance_map = corpse->GetMapId();
+                do 
+                {
+                    if(instance_map==mapid)
+                        break;
+
+                    InstanceTemplate const* instance = objmgr.GetInstanceTemplate(instance_map);
+                    instance_map = instance ? instance->parent : 0;
+                }
+                while (instance_map);
+
+                if (!instance_map)
+                {
+                    player->GetSession()->SendAreaTriggerMessage("You cannot enter %s while in a ghost mode", mapName);
+                    sLog.outDebug("MAP: Player '%s' doesn't has a corpse in instance '%s' and can't enter", player->GetName(), mapName);
+                    return false;
+                }
+                sLog.outDebug("MAP: Player '%s' has corpse in instance '%s' and can enter", player->GetName(), mapName);
+            }
+            else
+            {
+                sLog.outDebug("Map::CanEnter - player '%s' is dead but doesn't have a corpse!", player->GetName());
+            }
+        }
+
+        // TODO: move this to a map dependent location
+        /*if(i_data && i_data->IsEncounterInProgress())
+        {
+            sLog.outDebug("MAP: Player '%s' can't enter instance '%s' while an encounter is in progress.", player->GetName(), GetMapName());
+            player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
+            return(false);
+        }*/
+        return true;
+    }
+    else
+        return true;
 }
 
+void MapManager::DeleteInstance(uint32 mapid, uint32 instanceId, uint8 mode)
+{
+    Map *m = _GetBaseMap(mapid);
+    if (m && m->Instanceable())
+        ((MapInstanced*)m)->DestroyInstance(instanceId);
+}
+
 void MapManager::RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y)
 {
     bool remove_result = _GetBaseMap(mapid)->RemoveBones(guid, x, y);
@@ -204,7 +289,7 @@
 
 void MapManager::InitMaxInstanceId()
 {
-    i_MaxInstanceId = 0;
+    i_MaxInstanceId = sMapStore.GetNumRows();
 
     QueryResult *result = CharacterDatabase.Query( "SELECT MAX(id) FROM instance" );
     if( result )
@@ -213,3 +298,32 @@
         delete result;
     }
 }
+
+uint32 MapManager::GetNumInstances()
+{
+    uint32 ret = 0;
+    for(MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr)
+    {
+        Map *map = itr->second;
+        if(!map->Instanceable()) continue;
+        MapInstanced::InstancedMaps &maps = ((MapInstanced *)map)->GetInstancedMaps();
+        for(MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr)
+            if(mitr->second->IsDungeon()) ret++;
+    }
+    return ret;
+}
+
+uint32 MapManager::GetNumPlayersInInstances()
+{
+    uint32 ret = 0;
+    for(MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr)
+    {
+        Map *map = itr->second;
+        if(!map->Instanceable()) continue;
+        MapInstanced::InstancedMaps &maps = ((MapInstanced *)map)->GetInstancedMaps();
+        for(MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr)
+            if(mitr->second->IsDungeon())
+                ret += ((InstanceMap*)mitr->second)->GetPlayerList().size();
+    }
+    return ret;
+}
Index: src/game/Unit.cpp
===================================================================
--- src/game/Unit.cpp	(revision 5727)
+++ src/game/Unit.cpp	(working copy)
@@ -40,6 +40,7 @@
 #include "Totem.h"
 #include "BattleGround.h"
 #include "MovementGenerator.h"
+#include "MapInstancedSaveMgr.h"
 #include "GridNotifiersImpl.h"
 #include "CellImpl.h"
 
@@ -711,17 +712,40 @@
         else                                                // creature died
         {
             DEBUG_LOG("DealDamageNotPlayer");
+            Creature *cVictim = (Creature*)pVictim;
 
-            if(((Creature*)pVictim)->isPet())
-                pVictim->getHostilRefManager().deleteReferences();
+            if(cVictim->isPet())
+                cVictim->getHostilRefManager().deleteReferences();
             else
             {
-                pVictim->DeleteThreatList();
-                pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+                cVictim->DeleteThreatList();
+                cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
             }
             // Call creature just died function
-            if (((Creature*)pVictim)->AI())
-                ((Creature*)pVictim)->AI()->JustDied(this);
+            if (cVictim->AI())
+                cVictim->AI()->JustDied(this);
+
+            // Dungeon specific stuff
+            if(cVictim->GetInstanceId())
+            {
+                Map *m = cVictim->GetMap();
+                if(m->IsDungeon())
+                {
+                    if(m->IsRaid() || m->IsHeroic())
+                    {
+                        if(cVictim->isWorldBoss())
+                            ((InstanceMap *)m)->PermBindAllPlayers();
+                    }
+                    else
+                    {
+                        // the reset time is set but not added to the scheduler
+                        // until the players leave the instance
+                        time_t resettime = cVictim->GetRespawnTimeEx() + 2 * HOUR;
+                        if(InstanceSave *save = sInstanceSaveManager.GetInstanceSave(cVictim->GetInstanceId()))
+                            if(save->GetResetTime() < resettime) save->SetResetTime(resettime);
+                    }
+                }
+            }
         }
 
         // last damage from non duel opponent or opponent controlled creature
Index: src/game/ObjectMgr.h
===================================================================
--- src/game/ObjectMgr.h	(revision 5727)
+++ src/game/ObjectMgr.h	(working copy)
@@ -81,11 +81,17 @@
 extern ScriptMapMap sSpellScripts;
 extern ScriptMapMap sGameObjectScripts;
 extern ScriptMapMap sEventScripts;
+extern ScriptMapMap sWaypointScripts;
 
 struct AreaTrigger
 {
     uint8  requiredLevel;
     uint32 requiredItem;
+    uint32 requiredItem2;
+    uint32 heroicKey;
+    uint32 heroicKey2;
+    uint32 requiredQuest;
+    std::string requiredFailedText;
     uint32 target_mapId;
     float  target_X;
     float  target_Y;
@@ -102,7 +108,7 @@
     CellCorpseSet corpses;
 };
 typedef HM_NAMESPACE::hash_map<uint32/*cell_id*/,CellObjectGuids> CellObjectGuidsMap;
-typedef HM_NAMESPACE::hash_map<uint32/*mapid*/,CellObjectGuidsMap> MapObjectGuids;
+typedef HM_NAMESPACE::hash_map<uint32/*(mapid,spawnMode) pair*/,CellObjectGuidsMap> MapObjectGuids;
 
 typedef HM_NAMESPACE::hash_map<uint64/*(instance,guid) pair*/,time_t> RespawnTimes;
 
@@ -369,6 +375,8 @@
             return NULL;
         }
 
+        AreaTrigger const* GetGoBackTrigger(uint32 Map) const;
+
         ReputationOnKillEntry const* GetReputationOnKilEntry(uint32 id) const
         {
             RepOnKillMap::const_iterator itr = mRepOnKill.find(id);
@@ -409,6 +417,7 @@
         void LoadQuestStartScripts();
         void LoadEventScripts();
         void LoadSpellScripts();
+        void LoadWaypointScripts();
 
         bool LoadMangosStrings();
         void LoadMangosStringLocales();
@@ -419,6 +428,7 @@
         void LoadCreatureRespawnTimes();
         void LoadCreatureAddons();
         void LoadCreatureModelInfo();
+        void LoadWaypointData();
         void LoadEquipmentTemplates();
         void LoadGameObjectLocales();
         void LoadGameobjects();
@@ -495,9 +505,9 @@
 
         OpcodeTableMap opcodeTable;
 
-        CellObjectGuids const& GetCellObjectGuids(uint32 mapid, uint32 cell_id)
+        CellObjectGuids const& GetCellObjectGuids(uint16 mapid, uint8 spawnMode, uint32 cell_id)
         {
-            return mMapObjectGuids[mapid][cell_id];
+            return mMapObjectGuids[mapid+(spawnMode<<16)][cell_id];
         }
 
         CreatureData const* GetCreatureData(uint32 guid) const
Index: src/game/World.cpp
===================================================================
--- src/game/World.cpp	(revision 5727)
+++ src/game/World.cpp	(working copy)
@@ -55,6 +55,7 @@
 #include "RedZoneDistrict.h"
 #include "GridNotifiersImpl.h"
 #include "CellImpl.h"
+#include "MapInstancedSaveMgr.h"
 
 INSTANTIATE_SINGLETON_1( World );
 
@@ -376,6 +377,7 @@
     rate_values[RATE_HONOR] = sConfig.GetFloatDefault("Rate.Honor",1);
     rate_values[RATE_MINING_AMOUNT] = sConfig.GetFloatDefault("Rate.Mining.Amount",1);
     rate_values[RATE_MINING_NEXT]   = sConfig.GetFloatDefault("Rate.Mining.Next",1);
+    rate_values[RATE_INSTANCE_RESET_TIME] = sConfig.GetFloatDefault("Rate.InstanceResetTime",1);
     rate_values[RATE_TALENT] = sConfig.GetFloatDefault("Rate.Talent",1);
     if(rate_values[RATE_TALENT] < 0)
     {
@@ -435,6 +437,8 @@
     m_configs[CONFIG_INSTANCE_IGNORE_RAID]  = sConfig.GetBoolDefault("Instance.IgnoreRaid", false);
     m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfig.GetBoolDefault("Battleground.CastDeserter", true);
     m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true);
+    m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR]  = sConfig.GetIntDefault("Instance.ResetTimeHour", 4);
+    m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 1800000);
 
     m_configs[CONFIG_MAX_PRIMARY_TRADE_SKILL] = sConfig.GetIntDefault("MaxPrimaryTradeSkill", 2);
     m_configs[CONFIG_MIN_PETITION_SIGNS] = sConfig.GetIntDefault("MinPetitionSigns", 9);
@@ -617,6 +621,9 @@
     LoadDBCStores(m_dataPath);
     DetectDBCLang();
 
+    sLog.outString( "Loading InstanceTemplate" );
+    objmgr.LoadInstanceTemplate();
+
     ///- Clean up and pack instances
     sLog.outString( "Cleaning up instances..." );
     objmgr.CleanupInstances();                              // must be called before `creature_respawn`/`gameobject_respawn` tables
@@ -780,12 +787,12 @@
     sLog.outString( "Loading GameObject for quests..." );
     objmgr.LoadGameObjectForQuests();
 
-    sLog.outString( "Loading InstanceTemplate" );
-    objmgr.LoadInstanceTemplate();
-
     sLog.outString( "Loading BattleMasters..." );
     objmgr.LoadBattleMastersEntry();
 
+    sLog.outString( "Loading Waypoint Data..." );
+    objmgr.LoadWaypointData();
+
     ///- Handle outdated emails (delete/return)
     sLog.outString( "Returning old mails..." );
     objmgr.ReturnOrDeleteOldMails(false);
@@ -797,6 +804,7 @@
     objmgr.LoadSpellScripts();                              // must be after load Creature/Gameobject(Template/Data)
     objmgr.LoadGameObjectScripts();                         // must be after load Creature/Gameobject(Template/Data)
     objmgr.LoadEventScripts();                              // must be after load Creature/Gameobject(Template/Data)
+    objmgr.LoadWaypointScripts();
 
     sLog.outString( "Initializing Scripts..." );
     if(!LoadScriptingModule())
@@ -835,7 +843,6 @@
 
     ///- Initilize static helper structures
     AIRegistry::Initialize();
-    WaypointMovementGenerator<Creature>::Initialize();
     Player::InitVisibleBits();
     RedZone::Initialize();
 
@@ -1052,6 +1059,9 @@
     ///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove"
     ObjectAccessor::Instance().DoDelayedMovesAndRemoves();
 
+    // update the instance reset times
+    sInstanceSaveManager.Update();
+
     // And last, but not least handle the issued cli commands
     ProcessCliCommands();
 }
Index: src/game/Level2.cpp
===================================================================
--- src/game/Level2.cpp	(revision 5727)
+++ src/game/Level2.cpp	(working copy)
@@ -755,28 +755,24 @@
     float y = chr->GetPositionY();
     float z = chr->GetPositionZ();
     float o = chr->GetOrientation();
+    Map *map = chr->GetMap();
 
     Creature* pCreature = new Creature(NULL);
-    if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), chr->GetMapId(), x, y, z, o, id, (uint32)teamval))
+    if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map->GetId(), x, y, z, o, id, (uint32)teamval))
     {
         delete pCreature;
         return false;
     }
 
-    pCreature->SaveToDB();
+    pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
 
-    int32 guid = pCreature->GetDBTableGUIDLow();
+    int32 db_guid = pCreature->GetDBTableGUIDLow();
 
     // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
-    pCreature->LoadFromDB(guid, chr->GetInstanceId());
+    pCreature->LoadFromDB(db_guid, chr->GetInstanceId());
 
-    MapManager::Instance().GetMap(pCreature->GetMapId(), pCreature)->Add(pCreature);
-
-    CreatureData const* data = objmgr.GetCreatureData(guid);
-
-    if (data)
-        objmgr.AddCreatureToGrid(guid, data);
-
+    map->Add(pCreature);
+    objmgr.AddCreatureToGrid(db_guid, objmgr.GetCreatureData(db_guid));
     return true;
 }
 
@@ -2461,6 +2457,8 @@
         }
 
         Player* chr = m_session->GetPlayer();
+        Map *map = chr->GetMap();
+
         WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z) VALUES ('%u','%u','%f', '%f', '%f')",
             lowguid, point+1, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ());
 
@@ -2485,10 +2483,10 @@
         }
         WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), lowguid, point+1);
 
-        wpCreature->SaveToDB();
+        wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
         // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
         wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(), chr->GetInstanceId());
-        MapManager::Instance().GetMap(wpCreature->GetMapId(), wpCreature)->Add(wpCreature);
+        map->Add(wpCreature);
 
         PSendSysMessage(LANG_WAYPOINT_ADDED_NO, point+1);
         return true;
@@ -2555,6 +2553,7 @@
         PSendSysMessage("DEBUG: wp move, GUID: %u", lowguid);
 
         Player *chr = m_session->GetPlayer();
+        Map *map = chr->GetMap();
         {
             // Get the creature for which we read the waypoint
             /* impossible without entry
@@ -2582,10 +2581,10 @@
                     delete wpCreature2;
                     return false;
                 }
-                wpCreature2->SaveToDB();
+                wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
                 // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
                 wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), chr->GetInstanceId());
-                MapManager::Instance().GetMap(npcCreature->GetMapId(), npcCreature)->Add(wpCreature2);
+                map->Add(wpCreature2);
                 //MapManager::Instance().GetMap(npcCreature->GetMapId())->Add(wpCreature2);
             }
 
@@ -3049,6 +3048,7 @@
             uint32 id = VISUAL_WAYPOINT;
 
             Player *chr = m_session->GetPlayer();
+            Map *map = chr->GetMap();
             float o = chr->GetOrientation();
 
             Creature* wpCreature = new Creature(chr);
@@ -3064,10 +3064,10 @@
             // set "wpguid" column to the visual waypoint
             WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), lowguid, point);
 
-            wpCreature->SaveToDB();
+            wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
             // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
             wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(), chr->GetInstanceId());
-            MapManager::Instance().GetMap(wpCreature->GetMapId(), wpCreature)->Add(wpCreature);
+            map->Add(wpCreature);
             //MapManager::Instance().GetMap(wpCreature->GetMapId())->Add(wpCreature);
         }while( result->NextRow() );
 
@@ -3095,6 +3095,7 @@
 
         Player *chr = m_session->GetPlayer();
         float o = chr->GetOrientation();
+        Map *map = chr->GetMap();
 
         Creature* pCreature = new Creature(chr);
         if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), chr->GetMapId(), x, y, z, o, id, 0))
@@ -3105,9 +3106,9 @@
             return false;
         }
 
-        pCreature->SaveToDB();
+        pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
         pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), chr->GetInstanceId());
-        MapManager::Instance().GetMap(pCreature->GetMapId(), pCreature)->Add(pCreature);
+        map->Add(pCreature);
         //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "First Waypoint");
 
         // Cleanup memory
@@ -3143,6 +3144,7 @@
 
         Player *chr = m_session->GetPlayer();
         float o = chr->GetOrientation();
+        Map *map = chr->GetMap();
 
         Creature* pCreature = new Creature(chr);
         if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), chr->GetMapId(), x, y, z, o, id, 0))
@@ -3153,9 +3155,9 @@
             return false;
         }
 
-        pCreature->SaveToDB();
+        pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
         pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), chr->GetInstanceId());
-        MapManager::Instance().GetMap(pCreature->GetMapId(), pCreature)->Add(pCreature);
+        map->Add(pCreature);
         //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "Last Waypoint");
         // Cleanup memory
         delete result;
@@ -3288,22 +3290,19 @@
     float y = float(chr->GetPositionY());
     float z = float(chr->GetPositionZ());
     float o = float(chr->GetOrientation());
+    Map *map = chr->GetMap();
 
     float rot2 = sin(o/2);
     float rot3 = cos(o/2);
 
     GameObject* pGameObj = new GameObject(NULL);
-    uint32 lowGUID = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
+    uint32 db_lowGUID = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
 
-    if(!pGameObj->Create(lowGUID, goI->id, chr->GetMapId(), x, y, z, o, 0, 0, rot2, rot3, 0, 1))
+    if(!pGameObj->Create(db_lowGUID, goI->id, chr->GetMapId(), x, y, z, o, 0, 0, rot2, rot3, 0, 1))
     {
         delete pGameObj;
         return false;
     }
-    //pGameObj->SetZoneId(chr->GetZoneId());
-    pGameObj->SetMapId(chr->GetMapId());
-    //pGameObj->SetNameId(id);
-    sLog.outDebug(GetMangosString(LANG_GAMEOBJECT_CURRENT), goI->name, lowGUID, x, y, z, o);
 
     if( spawntimeSecs )
     {
@@ -3312,18 +3311,24 @@
         //sLog.outDebug("*** spawntimeSecs: %d", value);
     }
 
-    pGameObj->SaveToDB();
-    MapManager::Instance().GetMap(pGameObj->GetMapId(), pGameObj)->Add(pGameObj);
+    // fill the gameobject data and save to the db
+    pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
 
-    GameObjectData const* data = objmgr.GetGOData(lowGUID);
-
-    if (data)
+    // this will generate a new guid if the object is in an instance
+    if(!pGameObj->LoadFromDB(db_lowGUID, map->GetInstanceId()))
     {
-        objmgr.AddGameobjectToGrid(lowGUID, data);
+        delete pGameObj;
+        return false;
     }
+    
+    sLog.outDebug(GetMangosString(LANG_GAMEOBJECT_CURRENT), goI->name, db_lowGUID, x, y, z, o);
 
-    PSendSysMessage(LANG_GAMEOBJECT_ADD,id,goI->name,lowGUID,x,y,z);
+    map->Add(pGameObj);
 
+    // TODO: is it really necessary to add both the real and DB table guid here ?
+    objmgr.AddGameobjectToGrid(db_lowGUID, objmgr.GetGOData(db_lowGUID));
+
+    PSendSysMessage(LANG_GAMEOBJECT_ADD,id,goI->name,db_lowGUID,x,y,z);
     return true;
 }
 
Index: src/game/CharacterHandler.cpp
===================================================================
--- src/game/CharacterHandler.cpp	(revision 5727)
+++ src/game/CharacterHandler.cpp	(working copy)
@@ -60,9 +60,9 @@
 
     // NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure.
     // !!! NOTE: including unused `zone`,`online`
-    res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM,            "SELECT guid,account,data,name,race,class,position_x,position_y,position_z,map,orientation,taximask,cinematic,totaltime,leveltime,rest_bonus,logout_time,is_logout_resting,resettalents_cost,resettalents_time,trans_x,trans_y,trans_z,trans_o, transguid,gmstate,stable_slots,at_login,zone,online,pending_honor,last_honor_date,last_kill_date,taxi_path FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
-    res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP,           "SELECT leaderGuid FROM group_member WHERE memberGuid='%u'", GUID_LOPART(m_guid));
-    res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES,  "SELECT map,instance,leader FROM character_instance WHERE guid = '%u'", GUID_LOPART(m_guid));
+    res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM,            "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, gmstate, stable_slots, at_login, zone, online, pending_honor, last_honor_date, last_kill_date, taxi_path, dungeon_difficulty FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
+    res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP,           "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'", GUID_LOPART(m_guid));
+    res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES,  "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid));
     res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS,           "SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid));
     res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS,          "SELECT spell,slot,active FROM character_spell WHERE guid = '%u'", GUID_LOPART(m_guid));
     res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS,     "SELECT quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4 FROM character_queststatus WHERE guid = '%u'", GUID_LOPART(m_guid));
@@ -395,8 +395,15 @@
     else
         SetPlayer(pCurrChar);
 
-    pCurrChar->SendDungeonDifficulty();
+    Group *group = pCurrChar->GetGroup();
+    if(group && pCurrChar->getLevel() >= LEVELREQUIREMENT_HEROIC)
+    {
+        // the group leader may change the instance difficulty while the player is offline
+        pCurrChar->SetDifficulty(group->GetDifficulty());
+    }
 
+    pCurrChar->SendDungeonDifficulty(false);
+
     WorldPacket data( SMSG_LOGIN_VERIFY_WORLD, 20 );
     data << pCurrChar->GetMapId();
     data << pCurrChar->GetPositionX();
@@ -514,12 +521,15 @@
         pCurrChar->SetRank(0);
     }
 
-    if (!MapManager::Instance().GetMap(pCurrChar->GetMapId(), pCurrChar)->AddInstanced(pCurrChar))
+    if (!MapManager::Instance().GetMap(pCurrChar->GetMapId(), pCurrChar)->Add(pCurrChar))
     {
-        // TODO : Teleport to zone-in area
+        AreaTrigger const* at = objmgr.GetGoBackTrigger(pCurrChar->GetMapId());
+        if(at)
+            pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation());
+        else
+            pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation());
     }
 
-    MapManager::Instance().GetMap(pCurrChar->GetMapId(), pCurrChar)->Add(pCurrChar);
     ObjectAccessor::Instance().AddObject(pCurrChar);
     //sLog.outDebug("Player %s added to Map.",pCurrChar->GetName());
 
@@ -530,10 +540,10 @@
     pCurrChar->SetInGameTime( getMSTime() );
 
     // announce group about member online (must be after add to player list to receive announce to self)
-    if(pCurrChar->GetGroup())
+    if(group)
     {
         //pCurrChar->groupInfo.group->SendInit(this); // useless
-        pCurrChar->GetGroup()->SendUpdate();
+        group->SendUpdate();
     }
 
     // friend status
Index: src/game/WorldSession.cpp
===================================================================
--- src/game/WorldSession.cpp	(revision 5727)
+++ src/game/WorldSession.cpp	(working copy)
@@ -194,7 +194,7 @@
     objmgr.opcodeTable[ CMSG_GROUP_UNINVITE ]                   = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleGroupUninviteNameOpcode       );
     objmgr.opcodeTable[ CMSG_GROUP_UNINVITE_GUID ]              = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleGroupUninviteGuidOpcode       );
     objmgr.opcodeTable[ CMSG_GROUP_SET_LEADER ]                 = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleGroupSetLeaderOpcode          );
-    objmgr.opcodeTable[ CMSG_GROUP_DISBAND ]                    = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleGroupDisbandOpcode            );
+    objmgr.opcodeTable[ CMSG_GROUP_DISBAND ]                    = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleGroupLeaveOpcode              );
     objmgr.opcodeTable[ CMSG_GROUP_PASS_ON_LOOT_TOGGLE ]        = OpcodeHandler( STATUS_AUTHED,   &WorldSession::HandleGroupPassOnLootOpcode         );
     objmgr.opcodeTable[ CMSG_LOOT_METHOD ]                      = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleLootMethodOpcode              );
     objmgr.opcodeTable[ CMSG_LOOT_ROLL ]                        = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleLootRoll                      );
Index: src/game/Group.cpp
===================================================================
--- src/game/Group.cpp	(revision 5727)
+++ src/game/Group.cpp	(working copy)
@@ -26,6 +26,9 @@
 #include "Group.h"
 #include "ObjectAccessor.h"
 #include "BattleGround.h"
+#include "MapManager.h"
+#include "MapInstancedSaveMgr.h"
+#include "MapInstanced.h"
 
 Group::Group()
 {
@@ -59,6 +62,11 @@
         RollId.erase(itr);
         delete(r);
     }
+
+    // may unload some instance saves
+    for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
+        for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
+            itr->second.save->RemoveGroup(this);
 }
 
 bool Group::Create(const uint64 &guid, const char * name)
@@ -74,14 +82,22 @@
     if(!AddMember(guid, name))
         return false;
 
+    Player *player = objmgr.GetPlayer(guid);
+    if(player)
+    {
+        m_difficulty = player->GetDifficulty();
+    }
+    else
+        m_difficulty = DIFFICULTY_NORMAL;
+
     // store group in database
     CharacterDatabase.BeginTransaction();
-    CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
-    CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
-    CharacterDatabase.PExecute("INSERT INTO groups(leaderGuid,mainTank,mainAssistant,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,isRaid) "
-        "VALUES('%u','%u','%u','%u','%u','%u','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "',0)",
+    CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid ='%u'", GUID_LOPART(m_leaderGuid));
+    CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid ='%u'", GUID_LOPART(m_leaderGuid));
+    CharacterDatabase.PExecute("INSERT INTO groups(leaderGuid,mainTank,mainAssistant,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,isRaid,difficulty) "
+        "VALUES('%u','%u','%u','%u','%u','%u','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "',0,'%u')",
         GUID_LOPART(m_leaderGuid), GUID_LOPART(m_mainTank), GUID_LOPART(m_mainAssistant), uint32(m_lootMethod),
-        GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], m_targetIcons[7]);
+        GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], m_targetIcons[7], m_difficulty);
 
     for(Group::member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
     {
@@ -93,23 +109,29 @@
     return true;
 }
 
-bool Group::LoadGroupFromDB(const uint64 &leaderGuid)
+bool Group::LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result, bool loadMembers)
 {
-    //                                                     0         1              2           3           4              5      6      7      8      9      10     11     12     13
-    QueryResult *result = CharacterDatabase.PQuery("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid FROM groups WHERE leaderGuid='%u'", GUID_LOPART(leaderGuid));
+    bool external = true;
     if(!result)
-        return false;
+    {
+        external = false;
+        //                                       0          1              2           3           4              5      6      7      8      9      10     11     12     13      14
+        result = CharacterDatabase.PQuery("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty FROM groups WHERE leaderGuid ='%u'", GUID_LOPART(leaderGuid));
+        if(!result)
+            return false;
+    }
 
     m_leaderGuid = leaderGuid;
 
     // group leader not exist
     if(!objmgr.GetPlayerNameByGUID(m_leaderGuid, m_leaderName))
     {
-        delete result;
+        if(!external) delete result;
         return false;
     }
 
     m_groupType  = (*result)[13].GetBool() ? GROUPTYPE_RAID : GROUPTYPE_NORMAL;
+    m_difficulty = (*result)[14].GetUInt8();
     m_mainTank = (*result)[0].GetUInt64();
     m_mainAssistant = (*result)[1].GetUInt64();
     m_lootMethod = (LootMethod)(*result)[2].GetUInt8();
@@ -118,27 +140,21 @@
 
     for(int i=0; i<TARGETICONCOUNT; i++)
         m_targetIcons[i] = (*result)[5+i].GetUInt64();
-    delete result;
+    if(!external) delete result;
 
-    result = CharacterDatabase.PQuery("SELECT memberGuid,assistant,subgroup FROM group_member WHERE leaderGuid='%u'", GUID_LOPART(leaderGuid));
-    if(!result)
-        return false;
-
-    do
+    if(loadMembers)
     {
-        MemberSlot member;
-        member.guid      = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER);
+        result = CharacterDatabase.PQuery("SELECT memberGuid, assistant, subgroup FROM group_member WHERE leaderGuid ='%u'", GUID_LOPART(leaderGuid));
+        if(!result)
+            return false;
 
-        // skip non-existed member
-        if(!objmgr.GetPlayerNameByGUID(member.guid, member.name))
-            continue;
+        do
+        {
+            LoadMemberFromDB((*result)[0].GetUInt32(), (*result)[2].GetUInt8(), (*result)[1].GetBool());
+        } while( result->NextRow() );
+        delete result;
+    }
 
-        member.group     = (*result)[2].GetUInt8();
-        member.assistant = (*result)[1].GetBool();
-        m_memberSlots.push_back(member);
-    } while( result->NextRow() );
-    delete result;
-
     // group too small
     if(GetMembersCount() < 2)
         return false;
@@ -146,6 +162,21 @@
     return true;
 }
 
+bool Group::LoadMemberFromDB(uint32 guidLow, uint8 subgroup, bool assistant)
+{
+    MemberSlot member;
+    member.guid      = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER);
+
+    // skip non-existed member
+    if(!objmgr.GetPlayerNameByGUID(member.guid, member.name))
+        return false;
+
+    member.group     = subgroup;
+    member.assistant = assistant;
+    m_memberSlots.push_back(member);
+    return true;
+}
+
 bool Group::AddInvite(Player *player)
 {
     if(!player || player->GetGroupInvite() || player->GetGroup())
@@ -184,10 +215,14 @@
     Player *player = objmgr.GetPlayer(guid);
     if(player)
     {
+        if(!IsLeader(player->GetGUID()) && player->getLevel() >= LEVELREQUIREMENT_HEROIC && player->GetDifficulty() != GetDifficulty())
+        {
+            player->SetDifficulty(m_difficulty);
+            player->SendDungeonDifficulty(true);
+        }
         player->SetGroupUpdateFlag(GROUP_UPDATE_FULL);
         UpdatePlayerOutOfRange(player);
     }
-
     return true;
 }
 
@@ -212,6 +247,8 @@
             data.Initialize(SMSG_GROUP_LIST, 24);
             data << uint64(0) << uint64(0) << uint64(0);
             player->GetSession()->SendPacket(&data);
+
+            _homebindIfInstance(player);
         }
 
         if(leaderChanged)
@@ -272,6 +309,8 @@
         data.Initialize(SMSG_GROUP_LIST, 24);
         data << uint64(0) << uint64(0) << uint64(0);
         player->GetSession()->SendPacket(&data);
+
+        _homebindIfInstance(player);
     }
     RollId.clear();
     m_memberSlots.clear();
@@ -289,6 +328,8 @@
     CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
     CharacterDatabase.CommitTransaction();
 
+    ResetInstances(INSTANCE_RESET_GROUP_DISBAND, NULL);
+
     m_leaderGuid = 0;
     m_leaderName = "";
 }
@@ -808,7 +849,7 @@
             data << (uint8)m_lootMethod;                    // loot method
             data << (uint64)m_looterGuid;                   // looter guid
             data << (uint8)m_lootThreshold;                 // loot threshold
-            data << (uint8)0;                               // 2.1.0 unk
+            data << (uint8)m_difficulty;                     // Heroic Mod Group
         }
         player->GetSession()->SendPacket( &data );
     }
@@ -868,6 +909,8 @@
     if(!guid)
         return false;
 
+    Player *player = objmgr.GetPlayer(guid);
+
     MemberSlot member;
     member.guid      = guid;
     member.name      = name;
@@ -875,11 +918,14 @@
     member.assistant = isAssistant;
     m_memberSlots.push_back(member);
 
-    Player *player = objmgr.GetPlayer(guid);
     if(player)
     {
         player->SetGroupInvite(NULL);
         player->SetGroup(this, group);
+        // if the same group invites the player back, cancel the homebind timer
+        InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player->GetDifficulty());
+        if(bind && bind->save->GetInstanceId() == player->GetInstanceId())
+            player->m_InstanceValid = true;
     }
 
     if(!isRaidGroup())                                      // reset targetIcons for non-raid-groups
@@ -928,90 +974,39 @@
     if(slot==m_memberSlots.end())
         return;
 
-    // instance system leader change process
-    if (m_leaderGuid != slot->guid)
+    // update the group's bound instances when changing leaders
+    // TODO: not sure if this is correct
+    Player *player = objmgr.GetPlayer(guid);
+    if(player)
     {
-        // here we must unbind all instances bound to that leader on group members from the
-        // leader, and rebind them on the players
-        uint32 old_guid = m_leaderGuid;
-        uint32 new_guid = slot->guid;
-        std::set< uint32 > changed_bindings;
-        Player* player;
-        BoundInstancesMap::iterator i_BoundInstances;
-
-        // 1) rebind current associations in memory for group members
-        // 2) get current group associations from database (for unbind)
-        // combined because of query building in the iteration
-        if (GetMembersCount() > 0)
+        // first remove all permanent binds
+        for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
         {
-            std::ostringstream ss;
-            ss << "SELECT DISTINCT(map) FROM character_instance WHERE (guid IN (";
-
-            for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); )
+            for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end();)
             {
-                ss << GUID_LOPART(citr->guid);
-                player = objmgr.GetPlayer(citr->guid);
-                if(player && (citr->guid != old_guid))
+                if(itr->second.perm)
                 {
-                    for(i_BoundInstances = player->m_BoundInstances.begin(); i_BoundInstances != player->m_BoundInstances.end(); i_BoundInstances++)
-                    {
-                        if (i_BoundInstances->second.second == GUID_LOPART(old_guid))
-                        {
-
-                            i_BoundInstances->second.second = GUID_LOPART(new_guid);
-                            changed_bindings.insert(i_BoundInstances->first);
-                        }
-                    }
+                    // both the previous group leader and new one are online
+                    assert(itr->second.save->RemoveGroup(this));
+                    m_boundInstances[i].erase(itr++);
                 }
-                ++citr;
-                if (citr != m_memberSlots.end()) ss << ", ";
+                else
+                    ++itr;
             }
-            ss << ")) AND (leader = '" << GUID_LOPART(old_guid) << "')";
-            QueryResult* result = CharacterDatabase.Query(ss.str().c_str());
-            if (result)
-            {
-                do
-                {
-                    Field* fields = result->Fetch();
-                    changed_bindings.insert(fields[0].GetUInt32());
-                } while(result->NextRow());
-                delete result;
-            }
         }
 
-        // rebind changed associations in memory for old leader
-        player = objmgr.GetPlayer(old_guid);
-        if(player)
-        {
-            for (std::set< uint32 >::iterator i = changed_bindings.begin(); i != changed_bindings.end(); i++)
-            {
-                i_BoundInstances = player->m_BoundInstances.find(*i);
-                if (i_BoundInstances != player->m_BoundInstances.end()) i_BoundInstances->second.second = GUID_LOPART(new_guid);
-            }
-        }
-
-        // rebind changed associations in database
-        if (!changed_bindings.empty())
-        {
-            std::ostringstream ss;
-            ss << "UPDATE character_instance SET leader = '" << GUID_LOPART(new_guid) << "' WHERE (map IN (";
-            {
-                std::set< uint32 >::iterator i = changed_bindings.begin();
-                while (i != changed_bindings.end())
-                {
-                    ss << "'" << *i << "'";
-                    ++i;
-                    if (i != changed_bindings.end()) ss << ", ";
-                }
-            }
-            ss << ")) AND (leader = '" << GUID_LOPART(old_guid) << "')";
-            CharacterDatabase.Execute(ss.str().c_str());
-        }
+        // add the permanent binds of the player
+        // (assuming the player won't have solo binds when in group)
+        player->ConvertInstancesToGroup(true);
     }
 
+    // TODO: set a time limit to have this function run rarely cause it can be slow
     CharacterDatabase.BeginTransaction();
     CharacterDatabase.PExecute("UPDATE groups SET leaderGuid='%u' WHERE leaderGuid='%u'", GUID_LOPART(slot->guid), GUID_LOPART(m_leaderGuid));
     CharacterDatabase.PExecute("UPDATE group_member SET leaderGuid='%u' WHERE leaderGuid='%u'", GUID_LOPART(slot->guid), GUID_LOPART(m_leaderGuid));
+    CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderguid='%u' AND permanent = 1", GUID_LOPART(m_leaderGuid));
+    CharacterDatabase.PExecute("INSERT INTO group_instance SELECT guid, instance, permanent FROM character_instance WHERE guid = '%u' AND permanent = 1", GUID_LOPART(slot->guid));
+    CharacterDatabase.PExecute("UPDATE group_instance SET leaderGuid='%u' WHERE leaderGuid = '%u'", GUID_LOPART(slot->guid), GUID_LOPART(m_leaderGuid));
     CharacterDatabase.CommitTransaction();
 
     m_leaderGuid = slot->guid;
@@ -1206,3 +1201,153 @@
     // called from link()
     this->getTarget()->addLootValidatorRef(this);
 }
+
+void Group::SetDifficulty(uint8 difficulty)
+{
+    m_difficulty = difficulty;
+    CharacterDatabase.PExecute("UPDATE groups SET difficulty = %u WHERE leaderGuid ='%u'", m_difficulty, GUID_LOPART(m_leaderGuid));
+
+    for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+    {
+        Player *player = itr->getSource();
+        if(!player->GetSession() || player->getLevel() < LEVELREQUIREMENT_HEROIC)
+            continue;
+        player->SetDifficulty(difficulty);
+        player->SendDungeonDifficulty(true);
+    }
+}
+
+bool Group::InCombatToInstance(uint32 instanceId)
+{
+    for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+    {
+        Player *pPlayer = itr->getSource();
+        if(pPlayer->getAttackers().size() && pPlayer->GetInstanceId() == instanceId)
+            return true;
+    }
+    return false;
+}
+
+void Group::ResetInstances(uint8 method, Player* SendMsgTo)
+{
+    // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_DISBAND
+
+    // we assume that when the difficulty changes, all instances that can be reset will be
+    uint8 dif = GetDifficulty();
+     
+    for(BoundInstancesMap::iterator itr = m_boundInstances[dif].begin(); itr != m_boundInstances[dif].end();)
+    {
+        InstanceSave *p = itr->second.save;
+        const MapEntry *entry = sMapStore.LookupEntry(itr->first);
+        if(!entry || !p->CanReset())
+        {
+            ++itr;
+            continue;
+        }
+
+        if(method == INSTANCE_RESET_ALL)
+        {
+            // the "reset all instances" method can only reset normal maps
+            if(dif == DIFFICULTY_HEROIC || entry->map_type == MAP_RAID)
+            {
+                ++itr;
+                continue;
+            }
+        }
+
+        bool isEmpty = true;
+        // if the map is loaded, reset it
+        Map *map = MapManager::Instance().FindMap(p->GetMapId());
+        if(map && map->Instanceable())
+        {
+            Map *iMap = ((MapInstanced*)map)->FindMap(p->GetInstanceId());
+            if(iMap && iMap->IsDungeon())
+                isEmpty = ((InstanceMap*)iMap)->Reset(method);
+        }
+
+        if(SendMsgTo)
+        {
+            if(isEmpty) SendMsgTo->SendResetInstanceSuccess(p->GetMapId());
+            else SendMsgTo->SendResetInstanceFailed(0, p->GetMapId());
+        }
+
+        if(isEmpty || method == INSTANCE_RESET_GROUP_DISBAND || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
+        {
+            p->DeleteFromDB();
+            // i don't know for sure if hash_map iterators 
+            m_boundInstances[dif].erase(itr);
+            itr = m_boundInstances[dif].begin();
+            // this unloads the instance save unless online players are bound to it
+            // (eg. permanent binds or GM solo binds)
+            p->RemoveGroup(this);
+        }
+        else
+            ++itr;
+    }
+}
+
+InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, uint8 difficulty)
+{
+    // some instances only have one difficulty
+    const MapEntry* entry = sMapStore.LookupEntry(mapid);
+    if(!entry || !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL;
+
+    BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
+    if(itr != m_boundInstances[difficulty].end())
+        return &itr->second;
+    else
+        return NULL;
+}
+
+InstanceGroupBind* Group::BindToInstance(InstanceSave *save, bool permanent, bool load)
+{
+    if(save)
+    {
+        InstanceGroupBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()];
+        if(bind.save)
+        {
+            // when a boss is killed or when copying the players's binds to the group
+            if(permanent != bind.perm || save != bind.save)
+                if(!load) CharacterDatabase.PExecute("UPDATE group_instance SET instance = '%u', permanent = '%u' WHERE leaderGuid = '%u' AND instance = '%u'", save->GetInstanceId(), permanent, GUID_LOPART(GetLeaderGUID()), bind.save->GetInstanceId());
+        }
+        else
+            if(!load) CharacterDatabase.PExecute("INSERT INTO group_instance (leaderGuid, instance, permanent) VALUES ('%u', '%u', '%u')", GUID_LOPART(GetLeaderGUID()), save->GetInstanceId(), permanent);
+
+        if(bind.save != save)
+        {
+            if(bind.save) bind.save->RemoveGroup(this);
+            save->AddGroup(this);
+        }
+
+        bind.save = save;
+        bind.perm = permanent;
+        if(!load) sLog.outDebug("Group::BindToInstance: %d is now bound to map %d, instance %d, difficulty %d", GUID_LOPART(GetLeaderGUID()), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty());
+        return &bind;
+    }
+    else
+        return NULL;
+}
+
+void Group::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload)
+{
+    BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
+    if(itr != m_boundInstances[difficulty].end())
+    {
+        if(!unload) CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderGuid = '%u' AND instance = '%u'", GUID_LOPART(GetLeaderGUID()), itr->second.save->GetInstanceId());
+        itr->second.save->RemoveGroup(this);                // save can become invalid
+        m_boundInstances[difficulty].erase(itr);
+    }
+}
+
+void Group::_homebindIfInstance(Player *player)
+{
+    if(player && !player->isGameMaster() && MapManager::Instance().GetBaseMap(player->GetMapId())->IsDungeon())
+    {
+        // leaving the group in an instance, the homebind timer is started
+        // unless the player is permanently saved to the instance
+        InstanceSave *save = sInstanceSaveManager.GetInstanceSave(player->GetInstanceId());
+        InstancePlayerBind *playerBind = save ? player->GetBoundInstance(save->GetMapId(), save->GetDifficulty()) : NULL;
+        if(!playerBind || !playerBind->perm)
+            player->m_InstanceValid = false;
+    }
+}
Index: src/game/Player.cpp
===================================================================
--- src/game/Player.cpp	(revision 5727)
+++ src/game/Player.cpp	(working copy)
@@ -36,6 +36,7 @@
 #include "ChannelMgr.h"
 #include "MapManager.h"
 #include "MapInstanced.h"
+#include "MapInstancedSaveMgr.h"
 #include "GridNotifiers.h"
 #include "GridNotifiersImpl.h"
 #include "CellImpl.h"
@@ -270,8 +271,6 @@
     m_GuildIdInvited = 0;
     m_ArenaTeamIdInvited = 0;
 
-    m_dungeonDifficulty = DUNGEONDIFFICULTY_NORMAL;
-
     m_atLoginFlags = AT_LOGIN_NONE;
 
     m_dontMove = false;
@@ -358,6 +357,7 @@
     m_Loaded = false;
     m_HomebindTimer = 0;
     m_InstanceValid = true;
+    m_dungeonDifficulty = DIFFICULTY_NORMAL;
 
     memset(m_totalSpellMod, 0, sizeof(m_totalSpellMod));
 
@@ -420,6 +420,11 @@
     for(size_t x = 0; x < ItemSetEff.size(); x++)
         if(ItemSetEff[x])
             delete ItemSetEff[x];
+
+    // clean up player-instance binds, may unload some instance saves
+    for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
+        for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
+            itr->second.save->RemovePlayer(this);
 }
 
 bool Player::Create( uint32 guidlow, WorldPacket& data )
@@ -1538,12 +1543,11 @@
         {
             // yes, we are going to be homebind, avoid this action :)
             SetInstanceId(0);                               // reset instance id
-            m_BoundInstances.erase(mapid);                  // unbind our instance binding
                                                             // obtain new map
             map = MapManager::Instance().GetMap(mapid, this);
         }
 
-        if (map &&  map->AddInstanced(this))
+        if (map &&  map->CanEnter(this))
         {
             // send transfer packets
             WorldPacket data(SMSG_TRANSFER_PENDING, (4+4+4));
@@ -1564,11 +1568,8 @@
                 data << (uint32)mapid << (float)x << (float)y << (float)z << (float)orientation;
             }
             GetSession()->SendPacket( &data );
+            SendSavedInstances();
 
-            data.Initialize(SMSG_UNKNOWN_811, 4);
-            data << uint32(0);
-            GetSession()->SendPacket( &data );
-
             // remove from old map now
             if (oldmap) oldmap->Remove(this, false);
 
@@ -1590,6 +1591,11 @@
             SetMapId(mapid);
             Relocate(final_x, final_y, final_z, final_o);
 
+            // must set th