2 * Copyright (C) 2005-2009 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 "ObjectAccessor.h"
25 #include "Transports.h"
26 #include "GridDefines.h"
27 #include "MapInstanced.h"
28 #include "DestinationHolderImp.h"
32 #include "ObjectMgr.h"
34 #define CLASS_LOCK MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex>
35 INSTANTIATE_SINGLETON_2(MapManager
, CLASS_LOCK
);
36 INSTANTIATE_CLASS_MUTEX(MapManager
, ACE_Thread_Mutex
);
38 extern GridState
* si_GridStates
[]; // debugging code, should be deleted some day
40 MapManager::MapManager() : i_gridCleanUpDelay(sWorld
.getConfig(CONFIG_INTERVAL_GRIDCLEAN
))
42 i_timer
.SetInterval(sWorld
.getConfig(CONFIG_INTERVAL_MAPUPDATE
));
45 MapManager::~MapManager()
47 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
50 for(TransportSet::iterator i
= m_Transports
.begin(); i
!= m_Transports
.end(); ++i
)
53 Map::DeleteStateMachine();
57 MapManager::Initialize()
59 Map::InitStateMachine();
61 // debugging code, should be deleted some day
63 for(int i
=0;i
<MAX_GRID_STATE
; i
++)
65 i_GridStates
[i
] = si_GridStates
[i
];
67 i_GridStateErrorCount
= 0;
73 void MapManager::InitializeVisibilityDistanceInfo()
75 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
76 (*iter
).second
->InitVisibilityDistance();
79 // debugging code, should be deleted some day
80 void MapManager::checkAndCorrectGridStatesArray()
83 for(int i
=0;i
<MAX_GRID_STATE
; i
++)
85 if(i_GridStates
[i
] != si_GridStates
[i
])
87 sLog
.outError("MapManager::checkGridStates(), GridState: si_GridStates is currupt !!!");
89 si_GridStates
[i
] = i_GridStates
[i
];
92 // inner class checking only when compiled with debug
93 if(!si_GridStates
[i
]->checkMagic())
96 si_GridStates
[i
]->setMagic();
101 ++i_GridStateErrorCount
;
102 if(i_GridStateErrorCount
> 2)
103 assert(false); // force a crash. Too many errors
107 MapManager::_createBaseMap(uint32 id
)
109 Map
*m
= _findMap(id
);
115 const MapEntry
* entry
= sMapStore
.LookupEntry(id
);
116 if (entry
&& entry
->Instanceable())
118 m
= new MapInstanced(id
, i_gridCleanUpDelay
);
122 m
= new Map(id
, i_gridCleanUpDelay
, 0, 0);
131 Map
* MapManager::CreateMap(uint32 id
, const WorldObject
* obj
)
134 //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());
135 Map
*m
= _createBaseMap(id
);
137 if (m
&& (obj
->GetTypeId() == TYPEID_PLAYER
) && m
->Instanceable()) m
= ((MapInstanced
*)m
)->CreateInstance(id
, (Player
*)obj
);
142 Map
* MapManager::FindMap(uint32 mapid
, uint32 instanceId
) const
144 Map
*map
= _findMap(mapid
);
148 if(!map
->Instanceable())
149 return instanceId
== 0 ? map
: NULL
;
151 return ((MapInstanced
*)map
)->FindMap(instanceId
);
155 checks that do not require a map to be created
156 will send transfer error messages on fail
158 bool MapManager::CanPlayerEnter(uint32 mapid
, Player
* player
)
160 const MapEntry
*entry
= sMapStore
.LookupEntry(mapid
);
161 if(!entry
) return false;
162 const char *mapName
= entry
->name
[player
->GetSession()->GetSessionDbcLocale()];
164 if(entry
->map_type
== MAP_INSTANCE
|| entry
->map_type
== MAP_RAID
)
166 if (entry
->map_type
== MAP_RAID
)
168 // GMs can avoid raid limitations
169 if(!player
->isGameMaster() && !sWorld
.getConfig(CONFIG_INSTANCE_IGNORE_RAID
))
171 // can only enter in a raid group
172 Group
* group
= player
->GetGroup();
173 if (!group
|| !group
->isRaidGroup())
175 // probably there must be special opcode, because client has this string constant in GlobalStrings.lua
176 // TODO: this is not a good place to send the message
177 player
->GetSession()->SendAreaTriggerMessage("You must be in a raid group to enter %s instance", mapName
);
178 sLog
.outDebug("MAP: Player '%s' must be in a raid group to enter instance of '%s'", player
->GetName(), mapName
);
184 //The player has a heroic mode and tries to enter into instance which has no a heroic mode
185 MapDifficulty
const* mapDiff
= GetMapDifficultyData(entry
->MapID
,player
->GetDifficulty(entry
->map_type
== MAP_RAID
));
188 bool isHeroicTargetMap
= entry
->map_type
== MAP_RAID
189 ? (player
->GetRaidDifficulty() >= RAID_DIFFICULTY_10MAN_HEROIC
)
190 : (player
->GetDungeonDifficulty() >= DUNGEON_DIFFICULTY_HEROIC
);
192 //Send aborted message
193 // FIX ME: what about absent normal/heroic mode with specific players limit...
194 player
->SendTransferAborted(mapid
, TRANSFER_ABORT_DIFFICULTY
, isHeroicTargetMap
? DUNGEON_DIFFICULTY_HEROIC
: DUNGEON_DIFFICULTY_NORMAL
);
198 if (!player
->isAlive())
200 if(Corpse
*corpse
= player
->GetCorpse())
202 // let enter in ghost mode in instance that connected to inner instance with corpse
203 uint32 instance_map
= corpse
->GetMapId();
206 if(instance_map
==mapid
)
209 InstanceTemplate
const* instance
= objmgr
.GetInstanceTemplate(instance_map
);
210 instance_map
= instance
? instance
->parent
: 0;
212 while (instance_map
);
216 player
->GetSession()->SendAreaTriggerMessage("You cannot enter %s while in a ghost mode", mapName
);
217 sLog
.outDebug("MAP: Player '%s' doesn't has a corpse in instance '%s' and can't enter", player
->GetName(), mapName
);
220 sLog
.outDebug("MAP: Player '%s' has corpse in instance '%s' and can enter", player
->GetName(), mapName
);
224 sLog
.outDebug("Map::CanEnter - player '%s' is dead but doesn't have a corpse!", player
->GetName());
228 // TODO: move this to a map dependent location
229 /*if(i_data && i_data->IsEncounterInProgress())
231 sLog.outDebug("MAP: Player '%s' can't enter instance '%s' while an encounter is in progress.", player->GetName(), GetMapName());
232 player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
241 void MapManager::DeleteInstance(uint32 mapid
, uint32 instanceId
)
243 Map
*m
= _createBaseMap(mapid
);
244 if (m
&& m
->Instanceable())
245 ((MapInstanced
*)m
)->DestroyInstance(instanceId
);
248 void MapManager::RemoveBonesFromMap(uint32 mapid
, uint64 guid
, float x
, float y
)
250 bool remove_result
= _createBaseMap(mapid
)->RemoveBones(guid
, x
, y
);
254 sLog
.outDebug("Bones %u not found in world. Delete from DB also.", GUID_LOPART(guid
));
259 MapManager::Update(uint32 diff
)
261 i_timer
.Update(diff
);
262 if( !i_timer
.Passed() )
265 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
267 checkAndCorrectGridStatesArray(); // debugging code, should be deleted some day
268 iter
->second
->Update(i_timer
.GetCurrent());
271 ObjectAccessor::Instance().Update(i_timer
.GetCurrent());
272 for (TransportSet::iterator iter
= m_Transports
.begin(); iter
!= m_Transports
.end(); ++iter
)
273 (*iter
)->Update(i_timer
.GetCurrent());
275 i_timer
.SetCurrent(0);
278 void MapManager::DoDelayedMovesAndRemoves()
280 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
281 iter
->second
->DoDelayedMovesAndRemoves();
284 bool MapManager::ExistMapAndVMap(uint32 mapid
, float x
,float y
)
286 GridPair p
= MaNGOS::ComputeGridPair(x
,y
);
291 return Map::ExistMap(mapid
,gx
,gy
) && Map::ExistVMap(mapid
,gx
,gy
);
294 bool MapManager::IsValidMAP(uint32 mapid
)
296 MapEntry
const* mEntry
= sMapStore
.LookupEntry(mapid
);
297 return mEntry
&& (!mEntry
->IsDungeon() || objmgr
.GetInstanceTemplate(mapid
));
298 // TODO: add check for battleground template
301 void MapManager::UnloadAll()
303 for(MapMapType::iterator iter
=i_maps
.begin(); iter
!= i_maps
.end(); ++iter
)
304 iter
->second
->UnloadAll(true);
306 while(!i_maps
.empty())
308 delete i_maps
.begin()->second
;
309 i_maps
.erase(i_maps
.begin());
313 void MapManager::InitMaxInstanceId()
317 QueryResult
*result
= CharacterDatabase
.Query( "SELECT MAX(id) FROM instance" );
320 i_MaxInstanceId
= result
->Fetch()[0].GetUInt32();
325 uint32
MapManager::GetNumInstances()
328 for(MapMapType::iterator itr
= i_maps
.begin(); itr
!= i_maps
.end(); ++itr
)
330 Map
*map
= itr
->second
;
331 if(!map
->Instanceable()) continue;
332 MapInstanced::InstancedMaps
&maps
= ((MapInstanced
*)map
)->GetInstancedMaps();
333 for(MapInstanced::InstancedMaps::iterator mitr
= maps
.begin(); mitr
!= maps
.end(); ++mitr
)
334 if(mitr
->second
->IsDungeon()) ret
++;
339 uint32
MapManager::GetNumPlayersInInstances()
342 for(MapMapType::iterator itr
= i_maps
.begin(); itr
!= i_maps
.end(); ++itr
)
344 Map
*map
= itr
->second
;
345 if(!map
->Instanceable()) continue;
346 MapInstanced::InstancedMaps
&maps
= ((MapInstanced
*)map
)->GetInstancedMaps();
347 for(MapInstanced::InstancedMaps::iterator mitr
= maps
.begin(); mitr
!= maps
.end(); ++mitr
)
348 if(mitr
->second
->IsDungeon())
349 ret
+= ((InstanceMap
*)mitr
->second
)->GetPlayers().getSize();