2008-10-02 16:23:55 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2010-01-16 20:19:18 +03:00
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
2008-10-02 16:23:55 -05:00
*
* 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
2008-11-18 19:40:06 -06:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-02 16:23:55 -05:00
* 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, write to the Free Software
2008-11-18 19:40:06 -06:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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"
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-06-25 00:18:01 +02: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
{
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-08-08 05:25:45 +02:00
const InstanceTemplate * iTemplate = sObjectMgr . GetInstanceTemplate ( GetId ());
2010-04-07 19:14:10 +02:00
if ( ! iTemplate )
2008-10-02 16:23:55 -05: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-07-29 18:11:41 +02:00
MapDifficulty const * mapDiff = GetDownscaledMapDifficultyData ( GetId (), difficulty );
2009-10-17 15:51:44 -07:00
2009-07-16 11:49:00 +08: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-08-08 04:37:24 +02: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 ());
uint8 spawnMode = bracketEntry ? bracketEntry -> difficulty : REGULAR_DIFFICULTY ;
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-08-23 19:56:47 -07: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
}