2010-10-07 15:35:36 +02:00
/*
2011-01-01 15:01:13 +01:00
* Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "MapInstanced.h"
#include "ObjectMgr.h"
#include "MapManager.h"
2010-08-08 04:37:24 +02:00
#include "Battleground.h"
2008-10-02 16:23:55 -05:00
#include "VMapFactory.h"
#include "InstanceSaveMgr.h"
#include "World.h"
2010-11-29 07:50:31 +01:00
#include "Group.h"
2009-10-17 15:51:44 -07:00
2009-12-17 11:30:18 +01:00
MapInstanced :: MapInstanced ( uint32 id , time_t expiry ) : Map ( id , expiry , 0 , DUNGEON_DIFFICULTY_NORMAL )
2008-10-02 16:23:55 -05:00
{
// initialize instanced maps list
m_InstancedMaps . clear ();
// fill with zero
memset ( & GridMapReference , 0 , MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS * sizeof ( uint16 ));
}
2009-10-17 15:51:44 -07:00
2009-09-27 02:24:25 -07:00
void MapInstanced :: InitVisibilityDistance ()
{
2010-04-07 19:14:10 +02:00
if ( m_InstancedMaps . empty ())
2009-09-27 02:24:25 -07:00
return ;
//initialize visibility distances for all instance copies
for ( InstancedMaps :: iterator i = m_InstancedMaps . begin (); i != m_InstancedMaps . end (); ++ i )
2009-12-17 11:30:18 +01:00
{
2009-09-27 02:24:25 -07:00
( * i ). second -> InitVisibilityDistance ();
2009-12-17 11:30:18 +01:00
}
2009-09-27 02:24:25 -07:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
void MapInstanced :: Update ( const uint32 & t )
{
// take care of loaded GridMaps (when unused, unload it!)
Map :: Update ( t );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// update the instanced maps
InstancedMaps :: iterator i = m_InstancedMaps . begin ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
while ( i != m_InstancedMaps . end ())
{
2010-04-07 19:14:10 +02:00
if ( i -> second -> CanUnload ( t ))
2008-10-02 16:23:55 -05:00
{
2010-04-07 19:14:10 +02:00
if ( ! DestroyInstance ( i )) // iterator incremented
2009-08-06 16:14:13 -05:00
{
//m_unloadTimer
}
2008-10-02 16:23:55 -05:00
}
else
{
// update only here, because it may schedule some bad things before delete
i -> second -> Update ( t );
++ i ;
}
}
}
2009-10-17 15:51:44 -07:00
2009-08-25 15:12:22 -05:00
void MapInstanced :: DelayedUpdate ( const uint32 diff )
2008-10-02 16:23:55 -05:00
{
2008-12-08 16:34:03 -06:00
for ( InstancedMaps :: iterator i = m_InstancedMaps . begin (); i != m_InstancedMaps . end (); ++ i )
2009-08-25 15:12:22 -05:00
i -> second -> DelayedUpdate ( diff );
2009-10-17 15:51:44 -07:00
2009-08-25 15:12:22 -05:00
Map :: DelayedUpdate ( diff ); // this may be removed
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-08-25 15:12:22 -05:00
/*
2009-06-09 23:52:45 -05:00
void MapInstanced::RelocationNotify()
{
for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i)
i->second->RelocationNotify();
}
2009-08-25 15:12:22 -05:00
*/
2009-10-17 15:51:44 -07:00
2009-02-25 17:53:05 -06:00
void MapInstanced :: UnloadAll ()
2008-10-02 16:23:55 -05:00
{
// Unload instanced maps
2008-12-08 16:34:03 -06:00
for ( InstancedMaps :: iterator i = m_InstancedMaps . begin (); i != m_InstancedMaps . end (); ++ i )
2009-02-25 17:53:05 -06:00
i -> second -> UnloadAll ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// Delete the maps only after everything is unloaded to prevent crashes
2008-12-08 16:34:03 -06:00
for ( InstancedMaps :: iterator i = m_InstancedMaps . begin (); i != m_InstancedMaps . end (); ++ i )
2008-10-02 16:23:55 -05:00
delete i -> second ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
m_InstancedMaps . clear ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// Unload own grids (just dummy(placeholder) grids, neccesary to unload GridMaps!)
2009-02-25 17:53:05 -06:00
Map :: UnloadAll ();
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/*
- return the right instance for the object, based on its InstanceId
- create the instance if it's not created already
- the player is not actually added to the instance (only in InstanceMap::Add)
*/
2009-12-17 11:30:18 +01:00
Map * MapInstanced :: CreateInstance ( const uint32 mapId , Player * player )
2008-10-02 16:23:55 -05:00
{
2010-04-07 19:14:10 +02:00
if ( GetId () != mapId || ! player )
2009-12-17 11:30:18 +01:00
return NULL ;
Map * map = NULL ;
uint32 NewInstanceId = 0 ; // instanceId of the resulting map
2009-10-17 15:51:44 -07:00
2010-08-08 04:37:24 +02:00
if ( IsBattlegroundOrArena ())
2008-10-02 16:23:55 -05:00
{
2009-12-17 11:30:18 +01:00
// instantiate or find existing bg map for player
// the instance id is set in battlegroundid
2010-08-08 04:37:24 +02:00
NewInstanceId = player -> GetBattlegroundId ();
2010-04-07 19:14:10 +02:00
if ( ! NewInstanceId ) return NULL ;
2009-12-17 11:30:18 +01:00
map = _FindMap ( NewInstanceId );
2010-04-07 19:14:10 +02:00
if ( ! map )
2010-08-08 04:37:24 +02:00
map = CreateBattleground ( NewInstanceId , player -> GetBattleground ());
2009-05-16 14:52:41 -05:00
}
2009-12-17 11:30:18 +01:00
else
2009-05-16 14:52:41 -05:00
{
2009-12-17 11:30:18 +01:00
InstancePlayerBind * pBind = player -> GetBoundInstance ( GetId (), player -> GetDifficulty ( IsRaid ()));
InstanceSave * pSave = pBind ? pBind -> save : NULL ;
// the player's permanent player bind is taken into consideration first
// then the player's group bind and finally the solo bind.
2010-04-07 19:14:10 +02:00
if ( ! pBind || ! pBind -> perm )
2009-05-16 16:52:45 -05:00
{
2009-12-17 11:30:18 +01:00
InstanceGroupBind * groupBind = NULL ;
Group * group = player -> GetGroup ();
// use the player's difficulty setting (it may not be the same as the group's)
2010-04-19 17:03:10 +02:00
if ( group )
{
groupBind = group -> GetBoundInstance ( this );
if ( groupBind )
pSave = groupBind -> save ;
}
2009-05-16 16:52:45 -05:00
}
2010-04-07 19:14:10 +02:00
if ( pSave )
2009-12-17 11:30:18 +01:00
{
// solo/perm/group
NewInstanceId = pSave -> GetInstanceId ();
map = _FindMap ( NewInstanceId );
// it is possible that the save exists but the map doesn't
2010-04-07 19:14:10 +02:00
if ( ! map )
2009-12-17 11:30:18 +01:00
map = CreateInstance ( NewInstanceId , pSave , pSave -> GetDifficulty ());
}
else
{
// if no instanceId via group members or instance saves is found
// the instance will be created for the first time
2010-12-22 21:25:23 +01:00
NewInstanceId = sMapMgr -> GenerateInstanceId ();
2009-10-17 15:51:44 -07:00
2009-12-17 11:30:18 +01:00
Difficulty diff = player -> GetGroup () ? player -> GetGroup () -> GetDifficulty ( IsRaid ()) : player -> GetDifficulty ( IsRaid ());
map = CreateInstance ( NewInstanceId , NULL , diff );
}
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-12-17 11:30:18 +01:00
return map ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-12-17 11:30:18 +01:00
InstanceMap * MapInstanced :: CreateInstance ( uint32 InstanceId , InstanceSave * save , Difficulty difficulty )
2008-10-02 16:23:55 -05:00
{
// load/create a map
2010-06-25 00:18:01 +02:00
ACE_GUARD_RETURN ( ACE_Thread_Mutex , Guard , Lock , NULL );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// make sure we have a valid map id
const MapEntry * entry = sMapStore . LookupEntry ( GetId ());
2010-04-07 19:14:10 +02:00
if ( ! entry )
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "CreateInstance: no entry for map %d" , GetId ());
2010-07-30 20:04:28 +02:00
ASSERT ( false );
2008-10-02 16:23:55 -05:00
}
2010-12-22 20:23:47 +01:00
const InstanceTemplate * iTemplate = ObjectMgr :: GetInstanceTemplate ( GetId ());
2010-04-07 19:14:10 +02:00
if ( ! iTemplate )
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "CreateInstance: no instance template for map %d" , GetId ());
2010-07-30 20:04:28 +02:00
ASSERT ( false );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// some instances only have one difficulty
2010-08-30 15:25:15 +02:00
GetDownscaledMapDifficultyData ( GetId (), difficulty );
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outDebug ( "MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s" , save ? "" : "new " , InstanceId , GetId (), difficulty ? "heroic" : "normal" );
2009-10-17 15:51:44 -07:00
2009-07-16 11:49:00 +08:00
InstanceMap * map = new InstanceMap ( GetId (), GetGridExpiry (), InstanceId , difficulty , this );
ASSERT ( map -> IsDungeon ());
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
bool load_data = save != NULL ;
map -> CreateInstanceData ( load_data );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
m_InstancedMaps [ InstanceId ] = map ;
return map ;
}
2009-10-17 15:51:44 -07:00
2010-08-08 04:37:24 +02:00
BattlegroundMap * MapInstanced :: CreateBattleground ( uint32 InstanceId , Battleground * bg )
2008-10-02 16:23:55 -05:00
{
// load/create a map
2010-06-25 00:18:01 +02:00
ACE_GUARD_RETURN ( ACE_Thread_Mutex , Guard , Lock , NULL );
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outDebug ( "MapInstanced::CreateBattleground: map bg %d for %d created." , InstanceId , GetId ());
2009-10-17 15:51:44 -07:00
2010-02-15 15:31:27 +01:00
PvPDifficultyEntry const * bracketEntry = GetBattlegroundBracketByLevel ( bg -> GetMapId (), bg -> GetMinLevel ());
2010-08-30 15:25:15 +02:00
uint8 spawnMode ;
2010-09-12 01:40:27 +02:00
2010-08-30 15:25:15 +02:00
if ( bracketEntry )
spawnMode = bracketEntry -> difficulty ;
else
spawnMode = REGULAR_DIFFICULTY ;
2010-02-15 15:31:27 +01:00
2010-08-08 04:37:24 +02:00
BattlegroundMap * map = new BattlegroundMap ( GetId (), GetGridExpiry (), InstanceId , this , spawnMode );
ASSERT ( map -> IsBattlegroundOrArena ());
2009-12-17 11:30:18 +01:00
map -> SetBG ( bg );
bg -> SetBgMap ( map );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
m_InstancedMaps [ InstanceId ] = map ;
return map ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// increments the iterator after erase
2009-08-06 16:14:13 -05:00
bool MapInstanced :: DestroyInstance ( InstancedMaps :: iterator & itr )
2008-10-02 16:23:55 -05:00
{
2009-08-06 16:14:13 -05:00
itr -> second -> RemoveAllPlayers ();
2010-04-07 19:14:10 +02:00
if ( itr -> second -> HavePlayers ())
2009-08-06 16:14:13 -05:00
{
++ itr ;
return false ;
}
2009-10-17 15:51:44 -07:00
2009-02-25 17:53:05 -06:00
itr -> second -> UnloadAll ();
2008-10-02 16:23:55 -05:00
// should only unload VMaps if this is the last instance and grid unloading is enabled
2010-12-23 23:25:44 +01:00
if ( m_InstancedMaps . size () <= 1 && sWorld -> getBoolConfig ( CONFIG_GRID_UNLOAD ))
2008-10-02 16:23:55 -05:00
{
VMAP :: VMapFactory :: createOrGetVMapManager () -> unloadMap ( itr -> second -> GetId ());
// in that case, unload grids of the base map, too
// so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded
2009-02-25 17:53:05 -06:00
Map :: UnloadAll ();
2008-10-02 16:23:55 -05:00
}
// erase map
delete itr -> second ;
m_InstancedMaps . erase ( itr ++ );
2009-08-06 16:14:13 -05:00
return true ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-19 09:26:37 +02:00
bool MapInstanced :: CanEnter ( Player * /*player*/ )
2009-02-13 23:53:06 +01:00
{
2010-07-30 20:04:28 +02:00
//ASSERT(false);
2009-07-16 11:49:00 +08:00
return true ;
2009-02-13 23:53:06 +01:00
}