2 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "MapManager.h"
20 #include "InstanceSaveMgr.h"
21 #include "Policies/SingletonImp.h"
22 #include "Database/DatabaseEnv.h"
24 #include "Transports.h"
25 #include "GridDefines.h"
26 #include "MapInstanced.h"
27 #include "DestinationHolderImp.h"
31 #include "ObjectMgr.h"
33 #define CLASS_LOCK MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex>
34 INSTANTIATE_SINGLETON_2(MapManager
, CLASS_LOCK
);
35 INSTANTIATE_CLASS_MUTEX(MapManager
, ACE_Thread_Mutex
);
37 extern GridState
* si_GridStates
[]; // debugging code, should be deleted some day
39 MapManager::MapManager() : i_gridCleanUpDelay(sWorld
.getConfig(CONFIG_UINT32_INTERVAL_GRIDCLEAN
))
41 i_timer
.SetInterval(sWorld
.getConfig(CONFIG_UINT32_INTERVAL_MAPUPDATE
));
44 MapManager::~MapManager()
46 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
49 for(TransportSet::iterator i
= m_Transports
.begin(); i
!= m_Transports
.end(); ++i
)
52 Map::DeleteStateMachine();
56 MapManager::Initialize()
58 Map::InitStateMachine();
60 // debugging code, should be deleted some day
62 for(int i
=0;i
<MAX_GRID_STATE
; i
++)
64 i_GridStates
[i
] = si_GridStates
[i
];
66 i_GridStateErrorCount
= 0;
72 void MapManager::InitializeVisibilityDistanceInfo()
74 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
75 (*iter
).second
->InitVisibilityDistance();
78 // debugging code, should be deleted some day
79 void MapManager::checkAndCorrectGridStatesArray()
82 for(int i
=0;i
<MAX_GRID_STATE
; i
++)
84 if(i_GridStates
[i
] != si_GridStates
[i
])
86 sLog
.outError("MapManager::checkGridStates(), GridState: si_GridStates is currupt !!!");
88 si_GridStates
[i
] = i_GridStates
[i
];
91 // inner class checking only when compiled with debug
92 if(!si_GridStates
[i
]->checkMagic())
95 si_GridStates
[i
]->setMagic();
100 ++i_GridStateErrorCount
;
101 if(i_GridStateErrorCount
> 2)
102 assert(false); // force a crash. Too many errors
106 MapManager::_createBaseMap(uint32 id
)
108 Map
*m
= _findMap(id
);
114 const MapEntry
* entry
= sMapStore
.LookupEntry(id
);
115 if (entry
&& entry
->Instanceable())
117 m
= new MapInstanced(id
, i_gridCleanUpDelay
);
121 m
= new Map(id
, i_gridCleanUpDelay
, 0, REGULAR_DIFFICULTY
);
130 Map
* MapManager::CreateMap(uint32 id
, const WorldObject
* obj
)
133 //if(!obj->IsInWorld()) sLog.outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId());
134 Map
*m
= _createBaseMap(id
);
136 if (m
&& (obj
->GetTypeId() == TYPEID_PLAYER
) && m
->Instanceable()) m
= ((MapInstanced
*)m
)->CreateInstance(id
, (Player
*)obj
);
141 Map
* MapManager::FindMap(uint32 mapid
, uint32 instanceId
) const
143 Map
*map
= _findMap(mapid
);
147 if(!map
->Instanceable())
148 return instanceId
== 0 ? map
: NULL
;
150 return ((MapInstanced
*)map
)->FindMap(instanceId
);
154 checks that do not require a map to be created
155 will send transfer error messages on fail
157 bool MapManager::CanPlayerEnter(uint32 mapid
, Player
* player
)
159 const MapEntry
*entry
= sMapStore
.LookupEntry(mapid
);
160 if(!entry
) return false;
161 const char *mapName
= entry
->name
[player
->GetSession()->GetSessionDbcLocale()];
163 if(entry
->map_type
== MAP_INSTANCE
|| entry
->map_type
== MAP_RAID
)
165 if (entry
->map_type
== MAP_RAID
)
167 // GMs can avoid raid limitations
168 if(!player
->isGameMaster() && !sWorld
.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID
))
170 // can only enter in a raid group
171 Group
* group
= player
->GetGroup();
172 if (!group
|| !group
->isRaidGroup())
174 // probably there must be special opcode, because client has this string constant in GlobalStrings.lua
175 // TODO: this is not a good place to send the message
176 player
->GetSession()->SendAreaTriggerMessage("You must be in a raid group to enter %s instance", mapName
);
177 sLog
.outDebug("MAP: Player '%s' must be in a raid group to enter instance of '%s'", player
->GetName(), mapName
);
183 //The player has a heroic mode and tries to enter into instance which has no a heroic mode
184 MapDifficulty
const* mapDiff
= GetMapDifficultyData(entry
->MapID
,player
->GetDifficulty(entry
->map_type
== MAP_RAID
));
187 bool isRegularTargetMap
= player
->GetDifficulty(entry
->IsRaid()) == REGULAR_DIFFICULTY
;
189 //Send aborted message
190 // FIX ME: what about absent normal/heroic mode with specific players limit...
191 player
->SendTransferAborted(mapid
, TRANSFER_ABORT_DIFFICULTY
, isRegularTargetMap
? DUNGEON_DIFFICULTY_NORMAL
: DUNGEON_DIFFICULTY_HEROIC
);
195 if (!player
->isAlive())
197 if(Corpse
*corpse
= player
->GetCorpse())
199 // let enter in ghost mode in instance that connected to inner instance with corpse
200 uint32 instance_map
= corpse
->GetMapId();
203 if(instance_map
==mapid
)
206 InstanceTemplate
const* instance
= ObjectMgr::GetInstanceTemplate(instance_map
);
207 instance_map
= instance
? instance
->parent
: 0;
209 while (instance_map
);
213 player
->GetSession()->SendAreaTriggerMessage("You cannot enter %s while in a ghost mode", mapName
);
214 sLog
.outDebug("MAP: Player '%s' doesn't has a corpse in instance '%s' and can't enter", player
->GetName(), mapName
);
217 sLog
.outDebug("MAP: Player '%s' has corpse in instance '%s' and can enter", player
->GetName(), mapName
);
221 sLog
.outDebug("Map::CanEnter - player '%s' is dead but doesn't have a corpse!", player
->GetName());
225 // TODO: move this to a map dependent location
226 /*if(i_data && i_data->IsEncounterInProgress())
228 sLog.outDebug("MAP: Player '%s' can't enter instance '%s' while an encounter is in progress.", player->GetName(), GetMapName());
229 player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
238 void MapManager::DeleteInstance(uint32 mapid
, uint32 instanceId
)
240 Map
*m
= _createBaseMap(mapid
);
241 if (m
&& m
->Instanceable())
242 ((MapInstanced
*)m
)->DestroyInstance(instanceId
);
245 void MapManager::RemoveBonesFromMap(uint32 mapid
, uint64 guid
, float x
, float y
)
247 bool remove_result
= _createBaseMap(mapid
)->RemoveBones(guid
, x
, y
);
251 sLog
.outDebug("Bones %u not found in world. Delete from DB also.", GUID_LOPART(guid
));
256 MapManager::Update(uint32 diff
)
258 i_timer
.Update(diff
);
259 if( !i_timer
.Passed() )
262 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
264 checkAndCorrectGridStatesArray(); // debugging code, should be deleted some day
265 iter
->second
->Update((uint32
)i_timer
.GetCurrent());
268 for (TransportSet::iterator iter
= m_Transports
.begin(); iter
!= m_Transports
.end(); ++iter
)
269 (*iter
)->Update(i_timer
.GetCurrent());
271 i_timer
.SetCurrent(0);
274 void MapManager::RemoveAllObjectsInRemoveList()
276 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
277 iter
->second
->RemoveAllObjectsInRemoveList();
280 bool MapManager::ExistMapAndVMap(uint32 mapid
, float x
,float y
)
282 GridPair p
= MaNGOS::ComputeGridPair(x
,y
);
287 return Map::ExistMap(mapid
,gx
,gy
) && Map::ExistVMap(mapid
,gx
,gy
);
290 bool MapManager::IsValidMAP(uint32 mapid
)
292 MapEntry
const* mEntry
= sMapStore
.LookupEntry(mapid
);
293 return mEntry
&& (!mEntry
->IsDungeon() || ObjectMgr::GetInstanceTemplate(mapid
));
294 // TODO: add check for battleground template
297 void MapManager::UnloadAll()
299 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
300 iter
->second
->UnloadAll(true);
302 while(!i_maps
.empty())
304 delete i_maps
.begin()->second
;
305 i_maps
.erase(i_maps
.begin());
309 void MapManager::InitMaxInstanceId()
313 QueryResult
*result
= CharacterDatabase
.Query( "SELECT MAX(id) FROM instance" );
316 i_MaxInstanceId
= result
->Fetch()[0].GetUInt32();
321 uint32
MapManager::GetNumInstances()
324 for(MapMapType::iterator itr
= i_maps
.begin(); itr
!= i_maps
.end(); ++itr
)
326 Map
*map
= itr
->second
;
327 if(!map
->Instanceable()) continue;
328 MapInstanced::InstancedMaps
&maps
= ((MapInstanced
*)map
)->GetInstancedMaps();
329 for(MapInstanced::InstancedMaps::iterator mitr
= maps
.begin(); mitr
!= maps
.end(); ++mitr
)
330 if(mitr
->second
->IsDungeon()) ret
++;
335 uint32
MapManager::GetNumPlayersInInstances()
338 for(MapMapType::iterator itr
= i_maps
.begin(); itr
!= i_maps
.end(); ++itr
)
340 Map
*map
= itr
->second
;
341 if(!map
->Instanceable()) continue;
342 MapInstanced::InstancedMaps
&maps
= ((MapInstanced
*)map
)->GetInstancedMaps();
343 for(MapInstanced::InstancedMaps::iterator mitr
= maps
.begin(); mitr
!= maps
.end(); ++mitr
)
344 if(mitr
->second
->IsDungeon())
345 ret
+= ((InstanceMap
*)mitr
->second
)->GetPlayers().getSize();