aboutsummaryrefslogtreecommitdiff
path: root/src/game/Map.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/Map.cpp')
-rw-r--r--src/game/Map.cpp1157
1 files changed, 820 insertions, 337 deletions
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index b12c7b477c0..c6c74a74493 100644
--- a/src/game/Map.cpp
+++ b/src/game/Map.cpp
@@ -21,7 +21,6 @@
#include "MapManager.h"
#include "Player.h"
#include "GridNotifiers.h"
-#include "WorldSession.h"
#include "Log.h"
#include "GridStates.h"
#include "CellImpl.h"
@@ -36,6 +35,7 @@
#include "ScriptCalls.h"
#include "Group.h"
#include "MapRefManager.h"
+#include "Vehicle.h"
#include "MapInstanced.h"
#include "InstanceSaveMgr.h"
@@ -44,9 +44,6 @@
#define DEFAULT_GRID_EXPIRY 300
#define MAX_GRID_LOAD_TIME 50
-// magic *.map header
-const char MAP_MAGIC[] = "MAP_2.50";
-
GridState* si_GridStates[MAX_GRID_STATE];
Map::~Map()
@@ -54,11 +51,11 @@ Map::~Map()
UnloadAll();
}
-bool Map::ExistMap(uint32 mapid,int x,int y)
+bool Map::ExistMap(uint32 mapid,int gx,int gy)
{
int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1;
char* tmp = new char[len];
- snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),mapid,x,y);
+ snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),mapid,gx,gy);
FILE *pf=fopen(tmp,"rb");
@@ -69,9 +66,10 @@ bool Map::ExistMap(uint32 mapid,int x,int y)
return false;
}
- char magic[8];
- fread(magic,1,8,pf);
- if(strncmp(MAP_MAGIC,magic,8))
+ map_fileheader header;
+ fread(&header, sizeof(header), 1, pf);
+ if (header.mapMagic != uint32(MAP_MAGIC) ||
+ header.versionMagic != uint32(MAP_VERSION_MAGIC))
{
sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.",tmp);
delete [] tmp;
@@ -84,17 +82,17 @@ bool Map::ExistMap(uint32 mapid,int x,int y)
return true;
}
-bool Map::ExistVMap(uint32 mapid,int x,int y)
+bool Map::ExistVMap(uint32 mapid,int gx,int gy)
{
if(VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager())
{
if(vmgr->isMapLoadingEnabled())
{
// x and y are swapped !! => fixed now
- bool exists = vmgr->existsMap((sWorld.GetDataPath()+ "vmaps").c_str(), mapid, x,y);
+ bool exists = vmgr->existsMap((sWorld.GetDataPath()+ "vmaps").c_str(), mapid, gx,gy);
if(!exists)
{
- std::string name = vmgr->getDirFileName(mapid,x,y);
+ std::string name = vmgr->getDirFileName(mapid,gx,gy);
sLog.outError("VMap file '%s' is missing or point to wrong version vmap file, redo vmaps with latest vmap_assembler.exe program", (sWorld.GetDataPath()+"vmaps/"+name).c_str());
return false;
}
@@ -104,91 +102,70 @@ bool Map::ExistVMap(uint32 mapid,int x,int y)
return true;
}
-void Map::LoadVMap(int x,int y)
+void Map::LoadVMap(int gx,int gy)
{
// x and y are swapped !!
- int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld.GetDataPath()+ "vmaps").c_str(), GetId(), x,y);
+ int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld.GetDataPath()+ "vmaps").c_str(), GetId(), gx,gy);
switch(vmapLoadResult)
{
case VMAP::VMAP_LOAD_RESULT_OK:
- sLog.outDetail("VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), x,y, x,y);
+ sLog.outDetail("VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy);
break;
case VMAP::VMAP_LOAD_RESULT_ERROR:
- sLog.outDetail("Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), x,y, x,y);
+ sLog.outDetail("Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy);
break;
case VMAP::VMAP_LOAD_RESULT_IGNORED:
- DEBUG_LOG("Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), x,y, x,y);
+ DEBUG_LOG("Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy);
break;
}
}
-void Map::LoadMap(uint32 mapid, uint32 instanceid, int x,int y)
+void Map::LoadMap(int gx,int gy)
{
- if( instanceid != 0 )
+ if( i_InstanceId != 0 )
{
- if(GridMaps[x][y])
+ if(GridMaps[gx][gy])
return;
- Map* baseMap = const_cast<Map*>(MapManager::Instance().GetBaseMap(mapid));
-
- // load gridmap for base map
- if (!baseMap->GridMaps[x][y])
- baseMap->EnsureGridCreated(GridPair(63-x,63-y));
+ Map* baseMap = const_cast<Map*>(MapManager::Instance().GetBaseMap(i_id));
-//+++ if (!baseMap->GridMaps[x][y]) don't check for GridMaps[gx][gy], we need the management for vmaps
-// return;
+ // load grid map for base map
+ if (!baseMap->GridMaps[gx][gy])
+ baseMap->EnsureGridCreated(GridPair(63-gx,63-gy));
- ((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(x,y));
- GridMaps[x][y] = baseMap->GridMaps[x][y];
+ ((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(gx,gy));
+ GridMaps[gx][gy] = baseMap->GridMaps[gx][gy];
return;
}
//map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?)
- if(GridMaps[x][y])
+ if(GridMaps[gx][gy])
{
- sLog.outDetail("Unloading already loaded map %u before reloading.",mapid);
- delete (GridMaps[x][y]);
- GridMaps[x][y]=NULL;
+ sLog.outDetail("Unloading already loaded map %u before reloading.",i_id);
+ delete (GridMaps[gx][gy]);
+ GridMaps[gx][gy]=NULL;
}
// map file name
char *tmp=NULL;
- // Pihhan: dataPath length + "maps/" + 3+2+2+ ".map" length may be > 32 !
int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1;
tmp = new char[len];
- snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),mapid,x,y);
+ snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),i_id,gx,gy);
sLog.outDetail("Loading map %s",tmp);
// loading data
- FILE *pf=fopen(tmp,"rb");
- if(!pf)
+ GridMaps[gx][gy] = new GridMap();
+ if (!GridMaps[gx][gy]->loadData(tmp))
{
- delete [] tmp;
- return;
+ sLog.outError("Error load map file: \n %s\n", tmp);
}
-
- char magic[8];
- fread(magic,1,8,pf);
- if(strncmp(MAP_MAGIC,magic,8))
- {
- sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.",tmp);
- delete [] tmp;
- fclose(pf); //close file before return
- return;
- }
- delete [] tmp;
-
- GridMap * buf= new GridMap;
- fread(buf,1,sizeof(GridMap),pf);
- fclose(pf);
-
- GridMaps[x][y] = buf;
+ delete [] tmp;
}
-void Map::LoadMapAndVMap(uint32 mapid, uint32 instanceid, int x,int y)
+void Map::LoadMapAndVMap(int gx,int gy)
{
- LoadMap(mapid,instanceid,x,y);
- if(instanceid == 0)
- LoadVMap(x, y); // Only load the data for the base map
+ LoadMap(gx,gy);
+ if(i_InstanceId == 0)
+ LoadVMap(gx, gy); // Only load the data for the base map
}
void Map::InitStateMachine()
@@ -256,7 +233,7 @@ template<>
void Map::AddToGrid(Creature* obj, NGridType *grid, Cell const& cell)
{
// add to world object registry in grid
- if(obj->isPet() || obj->IsTempWorldObject)
+ if(obj->isWorldCreature() || obj->IsTempWorldObject)
{
(*grid)(cell.CellX(), cell.CellY()).AddWorldObject<Creature>(obj, obj->GetGUID());
}
@@ -308,7 +285,7 @@ template<>
void Map::RemoveFromGrid(Creature* obj, NGridType *grid, Cell const& cell)
{
// remove from world object registry in grid
- if(obj->isPet() || obj->IsTempWorldObject)
+ if(obj->isWorldCreature() || obj->IsTempWorldObject)
{
(*grid)(cell.CellX(), cell.CellY()).RemoveWorldObject<Creature>(obj, obj->GetGUID());
}
@@ -410,7 +387,7 @@ Map::EnsureGridCreated(const GridPair &p)
Guard guard(*this);
if(!getNGrid(p.x_coord, p.y_coord))
{
- sLog.outDebug("Loading grid[%u,%u] for map %u", p.x_coord, p.y_coord, i_id);
+ sLog.outDebug("Creating grid[%u,%u] for map %u instance %u", p.x_coord, p.y_coord, i_id, i_InstanceId);
setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_GRID_UNLOAD)),
p.x_coord, p.y_coord);
@@ -425,20 +402,20 @@ Map::EnsureGridCreated(const GridPair &p)
int gy=63-p.y_coord;
if(!GridMaps[gx][gy])
- Map::LoadMapAndVMap(i_id,i_InstanceId,gx,gy);
+ LoadMapAndVMap(gx,gy);
}
}
}
void
-Map::EnsureGridLoaded(const Cell &cell, Player *player)
+Map::EnsureGridLoadedAtEnter(const Cell &cell, Player *player)
{
- EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
- NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
+ NGridType *grid;
- assert(grid != NULL);
- if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY()))
+ if(EnsureGridLoaded(cell))
{
+ grid = getNGrid(cell.GridX(), cell.GridY());
+
if (player)
{
player->SendDelayResponse(MAX_GRID_LOAD_TIME);
@@ -449,19 +426,37 @@ Map::EnsureGridLoaded(const Cell &cell, Player *player)
DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id);
}
+ ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f);
+ grid->SetGridState(GRID_STATE_ACTIVE);
+ }
+ else
+ grid = getNGrid(cell.GridX(), cell.GridY());
+
+ if (player)
+ AddToGrid(player,grid,cell);
+}
+
+bool Map::EnsureGridLoaded(const Cell &cell)
+{
+ EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
+ NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
+
+ assert(grid != NULL);
+ if( !isGridObjectDataLoaded(cell.GridX(), cell.GridY()) )
+ {
+ sLog.outDebug("Loading grid[%u,%u] for map %u instance %u", cell.GridX(), cell.GridY(), i_id, i_InstanceId);
+
ObjectGridLoader loader(*grid, this, cell);
loader.LoadN();
- setGridObjectDataLoaded(true, cell.GridX(), cell.GridY());
// Add resurrectable corpses to world object list in grid
ObjectAccessor::Instance().AddCorpsesToGrid(GridPair(cell.GridX(),cell.GridY()),(*grid)(cell.CellX(), cell.CellY()), this);
- ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f);
- grid->SetGridState(GRID_STATE_ACTIVE);
+ setGridObjectDataLoaded(true,cell.GridX(), cell.GridY());
+ return true;
}
-
- if(player)
- AddToGrid(player,grid,cell);
+
+ return false;
}
void Map::LoadGrid(float x, float y)
@@ -480,7 +475,7 @@ bool Map::Add(Player *player)
// update player state for other player and visa-versa
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
Cell cell(p);
- EnsureGridLoaded(cell, player);
+ EnsureGridLoadedAtEnter(cell, player);
player->AddToWorld();
SendInitSelf(player);
@@ -508,7 +503,7 @@ Map::Add(T *obj)
Cell cell(p);
if(obj->isActiveObject())
- EnsureGridLoaded(cell);
+ EnsureGridLoadedAtEnter(cell);
else
EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
@@ -517,12 +512,14 @@ Map::Add(T *obj)
AddToGrid(obj,grid,cell);
obj->AddToWorld();
-
+
if(obj->isActiveObject())
AddToActive(obj);
DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY());
+ //something, such as vehicle, needs to be update immediately
+ //if(obj->GetTypeId() != TYPEID_UNIT)
UpdateObjectVisibility(obj,cell,p);
//AddNotifier(obj);
@@ -730,6 +727,13 @@ void Map::Update(const uint32 &t_diff)
}
}
}
+
+ if(plr->m_seer != plr && !plr->hasUnitState(UNIT_STAT_ONVEHICLE))
+ {
+ Trinity::PlayerVisibilityNotifier notifier(*plr);
+ VisitAll(plr->m_seer->GetPositionX(), plr->m_seer->GetPositionY(), World::GetMaxVisibleDistance(), notifier);
+ notifier.Notify();
+ }
}
// non-player active objects
@@ -747,33 +751,6 @@ void Map::Update(const uint32 &t_diff)
if(!obj->IsInWorld())
continue;
- // Update bindsight players
- /*if(obj->isType(TYPEMASK_UNIT))
- {
- if(!((Unit*)obj)->GetSharedVisionList().empty())
- for(SharedVisionList::const_iterator itr = ((Unit*)obj)->GetSharedVisionList().begin(); itr != ((Unit*)obj)->GetSharedVisionList().end(); ++itr)
- {
- if(!*itr)
- {
- sLog.outError("unit %u has invalid shared vision player, list size %u", obj->GetEntry(), ((Unit*)obj)->GetSharedVisionList().size());
- continue;
- }
- Trinity::PlayerVisibilityNotifier notifier(**itr);
- VisitAll(obj->GetPositionX(), obj->GetPositionY(), World::GetMaxVisibleDistance(), notifier);
- notifier.Notify();
- }
- }
- else */if(obj->GetTypeId() == TYPEID_DYNAMICOBJECT)
- {
- if(Unit *caster = ((DynamicObject*)obj)->GetCaster())
- if(caster->GetTypeId() == TYPEID_PLAYER && caster->GetUInt64Value(PLAYER_FARSIGHT) == obj->GetGUID())
- {
- Trinity::PlayerVisibilityNotifier notifier(*((Player*)caster));
- VisitAll(obj->GetPositionX(), obj->GetPositionY(), World::GetMaxVisibleDistance(), notifier);
- notifier.Notify();
- }
- }
-
CellPair standing_cell(Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));
// Check for correctness of standing_cell, it also avoids problems with update_cell
@@ -948,7 +925,7 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati
if( !old_cell.DiffGrid(new_cell) )
AddToGrid(player, oldGrid,new_cell);
else
- EnsureGridLoaded(new_cell, player);
+ EnsureGridLoadedAtEnter(new_cell, player);
}
AddUnitToNotify(player);
@@ -986,6 +963,17 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang
creature->Relocate(x, y, z, ang);
AddUnitToNotify(creature);
}
+
+ if(creature->isVehicle())
+ {
+ for(SeatMap::iterator itr = ((Vehicle*)creature)->m_Seats.begin(); itr != ((Vehicle*)creature)->m_Seats.end(); ++itr)
+ if(itr->second.passenger)
+ if(itr->second.passenger->GetTypeId() == TYPEID_PLAYER)
+ PlayerRelocation((Player*)itr->second.passenger, x, y, z, ang);
+ else
+ CreatureRelocation((Creature*)itr->second.passenger, x, y, z, ang);
+ }
+
assert(CheckGridIntegrity(creature,true));
}
@@ -1067,7 +1055,7 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell)
// in diff. grids but active creature
if(c->isActiveObject())
{
- EnsureGridLoaded(new_cell);
+ EnsureGridLoadedAtEnter(new_cell);
#ifdef TRINITY_DEBUG
if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0)
@@ -1178,7 +1166,11 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool unloadAll)
{
if (i_InstanceId == 0)
{
- if(GridMaps[gx][gy]) delete (GridMaps[gx][gy]);
+ if(GridMaps[gx][gy])
+ {
+ GridMaps[gx][gy]->unloadData();
+ delete GridMaps[gx][gy];
+ }
// x and y are swapped
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gy, gx);
}
@@ -1203,103 +1195,529 @@ void Map::UnloadAll()
}
}
-float Map::GetHeight(float x, float y, float z, bool pUseVmaps) const
+//*****************************
+// Grid function
+//*****************************
+GridMap::GridMap()
{
- GridPair p = Trinity::ComputeGridPair(x, y);
+ m_flags = 0;
+ // Area data
+ m_gridArea = 0;
+ m_area_map = NULL;
+ // Height level data
+ m_gridHeight = INVALID_HEIGHT;
+ m_gridGetHeight = &GridMap::getHeightFromFlat;
+ m_V9 = NULL;
+ m_V8 = NULL;
+ // Liquid data
+ m_liquidType = 0;
+ m_liquid_offX = 0;
+ m_liquid_offY = 0;
+ m_liquid_width = 0;
+ m_liquid_height = 0;
+ m_liquidLevel = INVALID_HEIGHT;
+ m_liquid_type = NULL;
+ m_liquid_map = NULL;
+}
- // half opt method
- int gx=(int)(32-x/SIZE_OF_GRIDS); //grid x
- int gy=(int)(32-y/SIZE_OF_GRIDS); //grid y
+GridMap::~GridMap()
+{
+ unloadData();
+}
- float lx=128*(32 -x/SIZE_OF_GRIDS - gx);
- float ly=128*(32 -y/SIZE_OF_GRIDS - gy);
+bool GridMap::loadData(char *filename)
+{
+ // Unload old data if exist
+ unloadData();
- // ensure GridMap is loaded
- const_cast<Map*>(this)->EnsureGridCreated(GridPair(63-gx,63-gy));
+ map_fileheader header;
+ // Not return error if file not found
+ FILE *in = fopen(filename, "rb");
+ if (!in)
+ return true;
+ fread(&header, sizeof(header),1,in);
+ if (header.mapMagic == uint32(MAP_MAGIC) &&
+ header.versionMagic == uint32(MAP_VERSION_MAGIC))
+ {
+ // loadup area data
+ if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize))
+ {
+ sLog.outError("Error loading map area data\n");
+ fclose(in);
+ return false;
+ }
+ // loadup height data
+ if (header.heightMapOffset && !loadHeihgtData(in, header.heightMapOffset, header.heightMapSize))
+ {
+ sLog.outError("Error loading map height data\n");
+ fclose(in);
+ return false;
+ }
+ // loadup liquid data
+ if (header.liquidMapOffset && !loadLiquidData(in, header.liquidMapOffset, header.liquidMapSize))
+ {
+ sLog.outError("Error loading map liquids data\n");
+ fclose(in);
+ return false;
+ }
+ fclose(in);
+ return true;
+ }
+ sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.", filename);
+ fclose(in);
+ return false;
+}
- // find raw .map surface under Z coordinates
- float mapHeight;
- if(GridMap* gmap = GridMaps[gx][gy])
+void GridMap::unloadData()
+{
+ if (m_area_map) delete[] m_area_map;
+ if (m_V9) delete[] m_V9;
+ if (m_V8) delete[] m_V8;
+ if (m_liquid_type) delete[] m_liquid_type;
+ if (m_liquid_map) delete[] m_liquid_map;
+ m_area_map = NULL;
+ m_V9 = NULL;
+ m_V8 = NULL;
+ m_liquid_type = NULL;
+ m_liquid_map = NULL;
+ m_gridGetHeight = &GridMap::getHeightFromFlat;
+}
+
+bool GridMap::loadAreaData(FILE *in, uint32 offset, uint32 size)
+{
+ map_areaHeader header;
+ fseek(in, offset, SEEK_SET);
+ fread(&header, sizeof(header), 1, in);
+ if (header.fourcc != uint32(MAP_AREA_MAGIC))
+ return false;
+
+ m_gridArea = header.gridArea;
+ if (!(header.flags & MAP_AREA_NO_AREA))
{
- int lx_int = (int)lx;
- int ly_int = (int)ly;
+ m_area_map = new uint16 [16*16];
+ fread(m_area_map, sizeof(uint16), 16*16, in);
+ }
+ return true;
+}
- lx -= lx_int;
- ly -= ly_int;
+bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 size)
+{
+ map_heightHeader header;
+ fseek(in, offset, SEEK_SET);
+ fread(&header, sizeof(header), 1, in);
+ if (header.fourcc != uint32(MAP_HEIGTH_MAGIC))
+ return false;
- float a,b,c;
- if (lx+ly < 1)
+ m_gridHeight = header.gridHeight;
+ if (!(header.flags & MAP_HEIGHT_NO_HIGHT))
+ {
+ if ((header.flags & MAP_HEIGHT_AS_INT16))
{
- if (lx > ly)
- {
- // 1
- float h1 = gmap->v9[lx_int][ly_int];
- float h2 = gmap->v9[lx_int+1][ly_int];
- float h5 = 2 * gmap->v8[lx_int][ly_int];
- a = h2-h1;
- b = h5-h1-h2;
- c = h1;
- }
- else
- {
- // 2
- float h1 = gmap->v9[lx_int][ly_int];
- float h3 = gmap->v9[lx_int][ly_int+1];
- float h5 = 2 * gmap->v8[lx_int][ly_int];
- a = h5 - h1 - h3;
- b = h3 - h1;
- c = h1;
- }
+ m_uint16_V9 = new uint16 [129*129];
+ m_uint16_V8 = new uint16 [128*128];
+ fread(m_uint16_V9, sizeof(uint16), 129*129, in);
+ fread(m_uint16_V8, sizeof(uint16), 128*128, in);
+ m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535;
+ m_gridGetHeight = &GridMap::getHeightFromUint16;
+ }
+ else if ((header.flags & MAP_HEIGHT_AS_INT8))
+ {
+ m_uint8_V9 = new uint8 [129*129];
+ m_uint8_V8 = new uint8 [128*128];
+ fread(m_uint8_V9, sizeof(uint8), 129*129, in);
+ fread(m_uint8_V8, sizeof(uint8), 128*128, in);
+ m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255;
+ m_gridGetHeight = &GridMap::getHeightFromUint8;
}
else
{
- if (lx > ly)
- {
- // 3
- float h2 = gmap->v9[lx_int+1][ly_int];
- float h4 = gmap->v9[lx_int+1][ly_int+1];
- float h5 = 2 * gmap->v8[lx_int][ly_int];
- a = h2 + h4 - h5;
- b = h4 - h2;
- c = h5 - h4;
- }
- else
- {
- // 4
- float h3 = gmap->v9[lx_int][ly_int+1];
- float h4 = gmap->v9[lx_int+1][ly_int+1];
- float h5 = 2 * gmap->v8[lx_int][ly_int];
- a = h4 - h3;
- b = h3 + h4 - h5;
- c = h5 - h4;
- }
+ m_V9 = new float [129*129];
+ m_V8 = new float [128*128];
+ fread(m_V9, sizeof(float), 129*129, in);
+ fread(m_V8, sizeof(float), 128*128, in);
+ m_gridGetHeight = &GridMap::getHeightFromFloat;
+ }
+ }
+ else
+ m_gridGetHeight = &GridMap::getHeightFromFlat;
+ return true;
+}
+
+bool GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 size)
+{
+ map_liquidHeader header;
+ fseek(in, offset, SEEK_SET);
+ fread(&header, sizeof(header), 1, in);
+ if (header.fourcc != uint32(MAP_LIQUID_MAGIC))
+ return false;
+
+ m_liquidType = header.liquidType;
+ m_liquid_offX = header.offsetX;
+ m_liquid_offY = header.offsetY;
+ m_liquid_width = header.width;
+ m_liquid_height= header.height;
+ m_liquidLevel = header.liquidLevel;
+
+ if (!(header.flags&MAP_LIQUID_NO_TYPE))
+ {
+ m_liquid_type = new uint8 [16*16];
+ fread(m_liquid_type, sizeof(uint8), 16*16, in);
+ }
+ if (!(header.flags&MAP_LIQUID_NO_HIGHT))
+ {
+ m_liquid_map = new float [m_liquid_width*m_liquid_height];
+ fread(m_liquid_map, sizeof(float), m_liquid_width*m_liquid_height, in);
+ }
+ return true;
+}
+
+uint16 GridMap::getArea(float x, float y)
+{
+ if (!m_area_map)
+ return m_gridArea;
+
+ x = 16 * (32 - x/SIZE_OF_GRIDS);
+ y = 16 * (32 - y/SIZE_OF_GRIDS);
+ int lx = (int)x & 15;
+ int ly = (int)y & 15;
+ return m_area_map[lx*16 + ly];
+}
+
+float GridMap::getHeightFromFlat(float x, float y) const
+{
+ return m_gridHeight;
+}
+
+float GridMap::getHeightFromFloat(float x, float y) const
+{
+ if (!m_V8 || !m_V9)
+ return m_gridHeight;
+
+ x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
+ y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);
+
+ int x_int = (int)x;
+ int y_int = (int)y;
+ x -= x_int;
+ y -= y_int;
+ x_int&=(MAP_RESOLUTION - 1);
+ y_int&=(MAP_RESOLUTION - 1);
+
+ // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
+ // +--------------> X
+ // | h1-------h2 Coordinates is:
+ // | | \ 1 / | h1 0,0
+ // | | \ / | h2 0,1
+ // | | 2 h5 3 | h3 1,0
+ // | | / \ | h4 1,1
+ // | | / 4 \ | h5 1/2,1/2
+ // | h3-------h4
+ // V Y
+ // For find height need
+ // 1 - detect triangle
+ // 2 - solve linear equation from triangle points
+ // Calculate coefficients for solve h = a*x + b*y + c
+
+ float a,b,c;
+ // Select triangle:
+ if (x+y < 1)
+ {
+ if (x > y)
+ {
+ // 1 triangle (h1, h2, h5 points)
+ float h1 = m_V9[(x_int )*129 + y_int];
+ float h2 = m_V9[(x_int+1)*129 + y_int];
+ float h5 = 2 * m_V8[x_int*128 + y_int];
+ a = h2-h1;
+ b = h5-h1-h2;
+ c = h1;
+ }
+ else
+ {
+ // 2 triangle (h1, h3, h5 points)
+ float h1 = m_V9[x_int*129 + y_int ];
+ float h3 = m_V9[x_int*129 + y_int+1];
+ float h5 = 2 * m_V8[x_int*128 + y_int];
+ a = h5 - h1 - h3;
+ b = h3 - h1;
+ c = h1;
+ }
+ }
+ else
+ {
+ if (x > y)
+ {
+ // 3 triangle (h2, h4, h5 points)
+ float h2 = m_V9[(x_int+1)*129 + y_int ];
+ float h4 = m_V9[(x_int+1)*129 + y_int+1];
+ float h5 = 2 * m_V8[x_int*128 + y_int];
+ a = h2 + h4 - h5;
+ b = h4 - h2;
+ c = h5 - h4;
+ }
+ else
+ {
+ // 4 triangle (h3, h4, h5 points)
+ float h3 = m_V9[(x_int )*129 + y_int+1];
+ float h4 = m_V9[(x_int+1)*129 + y_int+1];
+ float h5 = 2 * m_V8[x_int*128 + y_int];
+ a = h4 - h3;
+ b = h3 + h4 - h5;
+ c = h5 - h4;
+ }
+ }
+ // Calculate height
+ return a * x + b * y + c;
+}
+
+float GridMap::getHeightFromUint8(float x, float y) const
+{
+ if (!m_uint8_V8 || !m_uint8_V9)
+ return m_gridHeight;
+
+ x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
+ y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);
+
+ int x_int = (int)x;
+ int y_int = (int)y;
+ x -= x_int;
+ y -= y_int;
+ x_int&=(MAP_RESOLUTION - 1);
+ y_int&=(MAP_RESOLUTION - 1);
+
+ int32 a, b, c;
+ uint8 *V9_h1_ptr = &m_uint8_V9[x_int*128 + x_int + y_int];
+ if (x+y < 1)
+ {
+ if (x > y)
+ {
+ // 1 triangle (h1, h2, h5 points)
+ int32 h1 = V9_h1_ptr[ 0];
+ int32 h2 = V9_h1_ptr[129];
+ int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
+ a = h2-h1;
+ b = h5-h1-h2;
+ c = h1;
}
- float _mapheight = a * lx + b * ly + c;
-
- // In some very rare case this will happen. Need find a better way.
- if(lx_int == MAP_RESOLUTION) --lx_int;
- if(ly_int == MAP_RESOLUTION) --ly_int;
-
- /*
- float zi[4];
- // Probe 4 nearest points (except border cases)
- zi[0] = gmap->Z[lx_int][ly_int];
- zi[1] = lx < MAP_RESOLUTION-1 ? gmap->Z[lx_int+1][ly_int] : zi[0];
- zi[2] = ly < MAP_RESOLUTION-1 ? gmap->Z[lx_int][ly_int+1] : zi[0];
- zi[3] = lx < MAP_RESOLUTION-1 && ly < MAP_RESOLUTION-1 ? gmap->Z[lx_int+1][ly_int+1] : zi[0];
- // Recalculate them like if their x,y positions were in the range 0,1
- float b[4];
- b[0] = zi[0];
- b[1] = zi[1]-zi[0];
- b[2] = zi[2]-zi[0];
- b[3] = zi[0]-zi[1]-zi[2]+zi[3];
- // Normalize the dx and dy to be in range 0..1
- float fact_x = lx - lx_int;
- float fact_y = ly - ly_int;
- // Use the simplified bilinear equation, as described in [url="http://en.wikipedia.org/wiki/Bilinear_interpolation"]http://en.wikipedia.org/wiki/Bilinear_interpolation[/url]
- float _mapheight = b[0] + (b[1]*fact_x) + (b[2]*fact_y) + (b[3]*fact_x*fact_y);
-
- */
+ else
+ {
+ // 2 triangle (h1, h3, h5 points)
+ int32 h1 = V9_h1_ptr[0];
+ int32 h3 = V9_h1_ptr[1];
+ int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
+ a = h5 - h1 - h3;
+ b = h3 - h1;
+ c = h1;
+ }
+ }
+ else
+ {
+ if (x > y)
+ {
+ // 3 triangle (h2, h4, h5 points)
+ int32 h2 = V9_h1_ptr[129];
+ int32 h4 = V9_h1_ptr[130];
+ int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
+ a = h2 + h4 - h5;
+ b = h4 - h2;
+ c = h5 - h4;
+ }
+ else
+ {
+ // 4 triangle (h3, h4, h5 points)
+ int32 h3 = V9_h1_ptr[ 1];
+ int32 h4 = V9_h1_ptr[130];
+ int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
+ a = h4 - h3;
+ b = h3 + h4 - h5;
+ c = h5 - h4;
+ }
+ }
+ // Calculate height
+ return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight;
+}
+
+float GridMap::getHeightFromUint16(float x, float y) const
+{
+ if (!m_uint16_V8 || !m_uint16_V9)
+ return m_gridHeight;
+
+ x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
+ y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);
+
+ int x_int = (int)x;
+ int y_int = (int)y;
+ x -= x_int;
+ y -= y_int;
+ x_int&=(MAP_RESOLUTION - 1);
+ y_int&=(MAP_RESOLUTION - 1);
+
+ int32 a, b, c;
+ uint16 *V9_h1_ptr = &m_uint16_V9[x_int*128 + x_int + y_int];
+ if (x+y < 1)
+ {
+ if (x > y)
+ {
+ // 1 triangle (h1, h2, h5 points)
+ int32 h1 = V9_h1_ptr[ 0];
+ int32 h2 = V9_h1_ptr[129];
+ int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
+ a = h2-h1;
+ b = h5-h1-h2;
+ c = h1;
+ }
+ else
+ {
+ // 2 triangle (h1, h3, h5 points)
+ int32 h1 = V9_h1_ptr[0];
+ int32 h3 = V9_h1_ptr[1];
+ int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
+ a = h5 - h1 - h3;
+ b = h3 - h1;
+ c = h1;
+ }
+ }
+ else
+ {
+ if (x > y)
+ {
+ // 3 triangle (h2, h4, h5 points)
+ int32 h2 = V9_h1_ptr[129];
+ int32 h4 = V9_h1_ptr[130];
+ int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
+ a = h2 + h4 - h5;
+ b = h4 - h2;
+ c = h5 - h4;
+ }
+ else
+ {
+ // 4 triangle (h3, h4, h5 points)
+ int32 h3 = V9_h1_ptr[ 1];
+ int32 h4 = V9_h1_ptr[130];
+ int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
+ a = h4 - h3;
+ b = h3 + h4 - h5;
+ c = h5 - h4;
+ }
+ }
+ // Calculate height
+ return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight;
+}
+
+float GridMap::getLiquidLevel(float x, float y)
+{
+ if (!m_liquid_map)
+ return m_liquidLevel;
+
+ x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
+ y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);
+
+ int cx_int = ((int)x & (MAP_RESOLUTION-1)) - m_liquid_offY;
+ int cy_int = ((int)y & (MAP_RESOLUTION-1)) - m_liquid_offX;
+
+ if (cx_int < 0 || cx_int >=m_liquid_height)
+ return INVALID_HEIGHT;
+ if (cy_int < 0 || cy_int >=m_liquid_width )
+ return INVALID_HEIGHT;
+
+ return m_liquid_map[cx_int*m_liquid_width + cy_int];
+}
+
+uint8 GridMap::getTerrainType(float x, float y)
+{
+ if (!m_liquid_type)
+ return m_liquidType;
+
+ x = 16 * (32 - x/SIZE_OF_GRIDS);
+ y = 16 * (32 - y/SIZE_OF_GRIDS);
+ int lx = (int)x & 15;
+ int ly = (int)y & 15;
+ return m_liquid_type[lx*16 + ly];
+}
+
+// Get water state on map
+inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data)
+{
+ // Check water type (if no water return)
+ if (!m_liquid_type && !m_liquidType)
+ return LIQUID_MAP_NO_WATER;
+
+ // Get cell
+ float cx = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
+ float cy = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);
+
+ int x_int = (int)cx & (MAP_RESOLUTION-1);
+ int y_int = (int)cy & (MAP_RESOLUTION-1);
+
+ // Check water type in cell
+ uint8 type = m_liquid_type ? m_liquid_type[(x_int>>3)*16 + (y_int>>3)] : m_liquidType;
+ if (type == 0)
+ return LIQUID_MAP_NO_WATER;
+
+ // Check req liquid type mask
+ if (ReqLiquidType && !(ReqLiquidType&type))
+ return LIQUID_MAP_NO_WATER;
+
+ // Check water level:
+ // Check water height map
+ int lx_int = x_int - m_liquid_offY;
+ int ly_int = y_int - m_liquid_offX;
+ if (lx_int < 0 || lx_int >=m_liquid_height)
+ return LIQUID_MAP_NO_WATER;
+ if (ly_int < 0 || ly_int >=m_liquid_width )
+ return LIQUID_MAP_NO_WATER;
+
+ // Get water level
+ float liquid_level = m_liquid_map ? m_liquid_map[lx_int*m_liquid_width + ly_int] : m_liquidLevel;
+ // Get ground level (sub 0.2 for fix some errors)
+ float ground_level = getHeight(x, y);
+
+ // Check water level and ground level
+ if (liquid_level < ground_level || z < ground_level - 2)
+ return LIQUID_MAP_NO_WATER;
+
+ // All ok in water -> store data
+ if (data)
+ {
+ data->type = type;
+ data->level = liquid_level;
+ data->depth_level = ground_level;
+ }
+
+ // For speed check as int values
+ int delta = int((liquid_level - z) * 10);
+
+ // Get position delta
+ if (delta > 20) // Under water
+ return LIQUID_MAP_UNDER_WATER;
+ if (delta > 0 ) // In water
+ return LIQUID_MAP_IN_WATER;
+ if (delta > -1) // Walk on water
+ return LIQUID_MAP_WATER_WALK;
+ // Above water
+ return LIQUID_MAP_ABOVE_WATER;
+}
+
+inline GridMap *Map::GetGrid(float x, float y)
+{
+ // half opt method
+ int gx=(int)(32-x/SIZE_OF_GRIDS); //grid x
+ int gy=(int)(32-y/SIZE_OF_GRIDS); //grid y
+
+ // ensure GridMap is loaded
+ EnsureGridCreated(GridPair(63-gx,63-gy));
+
+ return GridMaps[gx][gy];
+}
+
+float Map::GetHeight(float x, float y, float z, bool pUseVmaps) const
+{
+ // find raw .map surface under Z coordinates
+ float mapHeight;
+ if(GridMap *gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ {
+ float _mapheight = gmap->getHeight(x,y);
+
// look from a bit higher pos to find the floor, ignore under surface case
if(z + 2.0f > _mapheight)
mapHeight = _mapheight;
@@ -1375,76 +1793,122 @@ float Map::GetVmapHeight(float x, float y, float z, bool useMaps) const
return vmapHeight;
}
-uint16 Map::GetAreaFlag(float x, float y ) const
+uint16 Map::GetAreaFlag(float x, float y, float z) const
{
- //local x,y coords
- float lx,ly;
- int gx,gy;
- GridPair p = Trinity::ComputeGridPair(x, y);
-
- // half opt method
- gx=(int)(32-x/SIZE_OF_GRIDS) ; //grid x
- gy=(int)(32-y/SIZE_OF_GRIDS); //grid y
-
- lx=16*(32 -x/SIZE_OF_GRIDS - gx);
- ly=16*(32 -y/SIZE_OF_GRIDS - gy);
- //DEBUG_LOG("my %d %d si %d %d",gx,gy,p.x_coord,p.y_coord);
-
- // ensure GridMap is loaded
- const_cast<Map*>(this)->EnsureGridCreated(GridPair(63-gx,63-gy));
-
- if(GridMaps[gx][gy])
- return GridMaps[gx][gy]->area_flag[(int)(lx)][(int)(ly)];
+ uint16 areaflag;
+ if(GridMap *gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ areaflag = gmap->getArea(x, y);
// this used while not all *.map files generated (instances)
else
- return GetAreaFlagByMapId(i_id);
+ areaflag = GetAreaFlagByMapId(i_id);
+
+ //FIXME: some hacks for areas above or underground for ground area
+ // required for area specific spells/etc, until map/vmap data
+ // not provided correct areaflag with this hacks
+ switch(areaflag)
+ {
+ // Acherus: The Ebon Hold (Plaguelands: The Scarlet Enclave)
+ case 1984: // Plaguelands: The Scarlet Enclave
+ case 2076: // Death's Breach (Plaguelands: The Scarlet Enclave)
+ case 2745: // The Noxious Pass (Plaguelands: The Scarlet Enclave)
+ if(z > 350.0f) areaflag = 2048; break;
+ // Acherus: The Ebon Hold (Eastern Plaguelands)
+ case 856: // The Noxious Glade (Eastern Plaguelands)
+ case 2456: // Death's Breach (Eastern Plaguelands)
+ if(z > 350.0f) areaflag = 1950; break;
+ // Dalaran
+ case 1593: // Crystalsong Forest
+ case 2484: // The Twilight Rivulet (Crystalsong Forest)
+ case 2492: // Forlorn Woods (Crystalsong Forest)
+ if (x > 5568.0f && x < 6116.0f && y > 282.0f && y < 982.0f && z > 563.0f) areaflag = 2153; break;
+ // Maw of Neltharion (cave)
+ case 164: // Dragonblight
+ case 1797: // Obsidian Dragonshrine (Dragonblight)
+ case 1827: // Wintergrasp
+ case 2591: // The Cauldron of Flames (Wintergrasp)
+ if (x > 4364.0f && x < 4632.0f && y > 1545.0f && y < 1886.0f && z < 200.0f) areaflag = 1853; break;
+ // Undercity (sewers enter and path)
+ case 179: // Tirisfal Glades
+ if (x > 1595.0f && x < 1699.0f && y > 535.0f && y < 643.5f && z < 30.5f) areaflag = 685; break;
+ // Undercity (Royal Quarter)
+ case 210: // Silverpine Forest
+ case 316: // The Shining Strand (Silverpine Forest)
+ case 438: // Lordamere Lake (Silverpine Forest)
+ if (x > 1237.0f && x < 1401.0f && y > 284.0f && y < 440.0f && z < -40.0f) areaflag = 685; break;
+ // Undercity (cave and ground zone, part of royal quarter)
+ case 607: // Ruins of Lordaeron (Tirisfal Glades)
+ // ground and near to ground (by city walls)
+ if(z > 0.0f)
+ {
+ if (x > 1510.0f && x < 1839.0f && y > 29.77f && y < 433.0f) areaflag = 685;
+ }
+ // more wide underground, part of royal quarter
+ else
+ {
+ if (x > 1299.0f && x < 1839.0f && y > 10.0f && y < 440.0f) areaflag = 685;
+ }
+ break;
+ // The Makers' Perch (ground) and Makers' Overlook (ground and cave)
+ case 1335: // Sholazar Basin
+ // The Makers' Perch ground (fast box)
+ if (x > 6100.0f && x < 6250.0f && y > 5650.0f && y < 5800.0f)
+ {
+ // nice slow circle
+ if ((x-6183.0f)*(x-6183.0f)+(y-5717.0f)*(y-5717.0f) < 2500.0f)
+ areaflag = 2189;
+ }
+ // Makers' Overlook (ground and cave)
+ else if (x > 5634.48f && x < 5774.53f && y < 3475.0f && z > 300.0f)
+ {
+ if(y > 3380.26f || y > 3265.0f && z < 360.0f) areaflag = 2187;
+ }
+ break;
+ // The Makers' Perch (underground)
+ case 2147: // The Stormwright's Shelf (Sholazar Basin)
+ if (x > 6199.0f && x < 6283.0f && y > 5705.0f && y < 5817.0f && z < 38.0f) areaflag = 2189; break;
+ // Makers' Overlook (deep cave)
+ case 267: // Icecrown
+ if (x > 5684.0f && x < 5798.0f && y > 3035.0f && y < 3367.0f && z < 358.0f) areaflag = 2187; break;
+ // Wyrmrest Temple (Dragonblight)
+ case 1814: // Path of the Titans (Dragonblight)
+ case 1897: // The Dragon Wastes (Dragonblight)
+ // fast box
+ if (x > 3400.0f && x < 3700.0f && y > 130.0f && y < 420.0f)
+ {
+ // nice slow circle
+ if ((x-3546.87f)*(x-3546.87f)+(y-272.71f)*(y-272.71f) < 19600.0f) areaflag = 1791;
+ }
+ break;
+ }
+
+ return areaflag;
}
uint8 Map::GetTerrainType(float x, float y ) const
{
- //local x,y coords
- float lx,ly;
- int gx,gy;
-
- // half opt method
- gx=(int)(32-x/SIZE_OF_GRIDS) ; //grid x
- gy=(int)(32-y/SIZE_OF_GRIDS); //grid y
-
- lx=16*(32 -x/SIZE_OF_GRIDS - gx);
- ly=16*(32 -y/SIZE_OF_GRIDS - gy);
-
- // ensure GridMap is loaded
- const_cast<Map*>(this)->EnsureGridCreated(GridPair(63-gx,63-gy));
-
- if(GridMaps[gx][gy])
- return GridMaps[gx][gy]->terrain_type[(int)(lx)][(int)(ly)];
+ if(GridMap *gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ return gmap->getTerrainType(x, y);
else
return 0;
}
-float Map::GetWaterLevel(float x, float y ) const
+ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data) const
{
- //local x,y coords
- float lx,ly;
- int gx,gy;
-
- // half opt method
- gx=(int)(32-x/SIZE_OF_GRIDS) ; //grid x
- gy=(int)(32-y/SIZE_OF_GRIDS); //grid y
-
- lx=128*(32 -x/SIZE_OF_GRIDS - gx);
- ly=128*(32 -y/SIZE_OF_GRIDS - gy);
-
- // ensure GridMap is loaded
- const_cast<Map*>(this)->EnsureGridCreated(GridPair(63-gx,63-gy));
+ if(GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ return gmap->getLiquidStatus(x, y, z, ReqLiquidType, data);
+ else
+ return LIQUID_MAP_NO_WATER;
+}
- if(GridMaps[gx][gy])
- return GridMaps[gx][gy]->liquid_level[(int)(lx)][(int)(ly)];
+float Map::GetWaterLevel(float x, float y ) const
+{
+ if(GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ return gmap->getLiquidLevel(x, y);
else
return 0;
}
-uint32 Map::GetAreaId(uint16 areaflag,uint32 map_id)
+uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id)
{
AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id);
@@ -1454,7 +1918,7 @@ uint32 Map::GetAreaId(uint16 areaflag,uint32 map_id)
return 0;
}
-uint32 Map::GetZoneId(uint16 areaflag,uint32 map_id)
+uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id)
{
AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id);
@@ -1464,26 +1928,37 @@ uint32 Map::GetZoneId(uint16 areaflag,uint32 map_id)
return 0;
}
-bool Map::IsInWater(float x, float y, float pZ) const
+void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id)
{
- // This method is called too often to use vamps for that (4. parameter = false).
- // The pZ pos is taken anyway for future use
- float z = GetHeight(x,y,pZ,false); // use .map base surface height
+ AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id);
- // underground or instance without vmap
- if(z <= INVALID_HEIGHT)
- return false;
+ areaid = entry ? entry->ID : 0;
+ zoneid = entry ? (( entry->zone != 0 ) ? entry->zone : entry->ID) : 0;
+}
- float water_z = GetWaterLevel(x,y);
- uint8 flag = GetTerrainType(x,y);
- return (z < (water_z-2)) && (flag & 0x01);
+bool Map::IsInWater(float x, float y, float pZ) const
+{
+ // Check surface in x, y point for liquid
+ if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ {
+ LiquidData liquid_status;
+ if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, &liquid_status))
+ {
+ if (liquid_status.level - liquid_status.depth_level > 2)
+ return true;
+ }
+ }
+ return false;
}
bool Map::IsUnderWater(float x, float y, float z) const
{
- float water_z = GetWaterLevel(x,y);
- uint8 flag = GetTerrainType(x,y);
- return (z < (water_z-2)) && (flag & 0x01);
+ if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ {
+ if (getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER|MAP_LIQUID_TYPE_OCEAN)&LIQUID_MAP_UNDER_WATER)
+ return true;
+ }
+ return false;
}
bool Map::CheckGridIntegrity(Creature* c, bool moved) const
@@ -1573,7 +2048,8 @@ void Map::SendInitTransports( Player * player )
for (MapManager::TransportSet::iterator i = tset.begin(); i != tset.end(); ++i)
{
- if((*i) != player->GetTransport()) // send data for current transport in other place
+ // send data for current transport in other place
+ if((*i) != player->GetTransport() && (*i)->GetMapId()==i_id)
{
hasTransport = true;
(*i)->BuildCreateUpdateBlockForPlayer(&transData, player);
@@ -1600,7 +2076,7 @@ void Map::SendRemoveTransports( Player * player )
// except used transport
for (MapManager::TransportSet::iterator i = tset.begin(); i != tset.end(); ++i)
- if(player->GetTransport() != (*i))
+ if((*i) != player->GetTransport() && (*i)->GetMapId()!=i_id)
(*i)->BuildOutOfRangeUpdateBlock(&transData);
WorldPacket packet;
@@ -1657,7 +2133,7 @@ void Map::RemoveAllObjectsInRemoveList()
switch(obj->GetTypeId())
{
case TYPEID_UNIT:
- if(!((Creature*)obj)->isPet())
+ if(!((Creature*)obj)->isWorldCreature())
SwitchGridContainers((Creature*)obj, on);
break;
}
@@ -1804,8 +2280,9 @@ template void Map::Remove(DynamicObject *, bool);
/* ******* Dungeon Instance Maps ******* */
InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
- : Map(id, expiry, InstanceId, SpawnMode), i_data(NULL),
- m_resetAfterUnload(false), m_unloadWhenEmpty(false)
+ : Map(id, expiry, InstanceId, SpawnMode),
+ m_resetAfterUnload(false), m_unloadWhenEmpty(false),
+ i_data(NULL), i_script_id(0)
{
// the timer is started by default, and stopped when the first player joins
// this make sure it gets unloaded if for some reason no player joins
@@ -1834,10 +2311,10 @@ bool InstanceMap::CanEnter(Player *player)
}
// cannot enter if the instance is full (player cap), GMs don't count
- InstanceTemplate const* iTemplate = objmgr.GetInstanceTemplate(GetId());
- if (!player->isGameMaster() && GetPlayersCountExceptGMs() >= iTemplate->maxPlayers)
+ uint32 maxPlayers = GetMaxPlayers();
+ if (!player->isGameMaster() && GetPlayersCountExceptGMs() >= maxPlayers)
{
- sLog.outDetail("MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), iTemplate->maxPlayers, player->GetName());
+ sLog.outDetail("MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName());
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
return false;
}
@@ -1867,79 +2344,81 @@ bool InstanceMap::Add(Player *player)
if(!CanEnter(player))
return false;
- // get or create an instance save for the map
- InstanceSave *mapSave = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
- if(!mapSave)
+ // Dungeon only code
+ if(IsDungeon())
{
- sLog.outDetail("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId());
- mapSave = sInstanceSaveManager.AddInstanceSave(GetId(), GetInstanceId(), GetSpawnMode(), 0, true);
- }
-
- // check for existing instance binds
- InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), GetSpawnMode());
- if(playerBind && playerBind->perm)
- {
- // cannot enter other instances if bound permanently
- if(playerBind->save != mapSave)
+ // get or create an instance save for the map
+ InstanceSave *mapSave = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
+ if(!mapSave)
{
- sLog.outError("InstanceMap::Add: player %s(%d) is permanently bound to instance %d,%d,%d,%d,%d,%d but he is being put in instance %d,%d,%d,%d,%d,%d", player->GetName(), player->GetGUIDLow(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset());
- assert(false);
+ sLog.outDetail("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId());
+ mapSave = sInstanceSaveManager.AddInstanceSave(GetId(), GetInstanceId(), GetSpawnMode(), 0, true);
}
- }
- else
- {
- Group *pGroup = player->GetGroup();
- if(pGroup)
+
+ // check for existing instance binds
+ InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), GetSpawnMode());
+ if(playerBind && playerBind->perm)
{
- // solo saves should be reset when entering a group
- InstanceGroupBind *groupBind = pGroup->GetBoundInstance(GetId(), GetSpawnMode());
- if(playerBind)
+ // cannot enter other instances if bound permanently
+ if(playerBind->save != mapSave)
{
- sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
- if(groupBind) sLog.outError("InstanceMap::Add: the group is bound to instance %d,%d,%d,%d,%d,%d", groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
- sLog.outError("InstanceMap::Add: do not let player %s enter instance otherwise crash will happen", player->GetName());
- return false;
- //player->UnbindInstance(GetId(), GetSpawnMode());
- //assert(false);
+ sLog.outError("InstanceMap::Add: player %s(%d) is permanently bound to instance %d,%d,%d,%d,%d,%d but he is being put in instance %d,%d,%d,%d,%d,%d", player->GetName(), player->GetGUIDLow(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset());
+ assert(false);
}
- // bind to the group or keep using the group save
- if(!groupBind)
- pGroup->BindToInstance(mapSave, false);
- else
+ }
+ else
+ {
+ Group *pGroup = player->GetGroup();
+ if(pGroup)
{
- // cannot jump to a different instance without resetting it
- if(groupBind->save != mapSave)
+ // solo saves should be reset when entering a group
+ InstanceGroupBind *groupBind = pGroup->GetBoundInstance(GetId(), GetSpawnMode());
+ if(playerBind)
{
- sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d but he is in group %d which is bound to instance %d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), GUID_LOPART(pGroup->GetLeaderGUID()), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty());
- if(mapSave)
- sLog.outError("MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount());
- else
- sLog.outError("MapSave NULL");
- if(groupBind->save)
- sLog.outError("GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
- else
- sLog.outError("GroupBind save NULL");
- assert(false);
+ sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
+ if(groupBind) sLog.outError("InstanceMap::Add: the group is bound to instance %d,%d,%d,%d,%d,%d", groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
+ //assert(false);
+ return false;
}
- // if the group/leader is permanently bound to the instance
- // players also become permanently bound when they enter
- if(groupBind->perm)
+ // bind to the group or keep using the group save
+ if(!groupBind)
+ pGroup->BindToInstance(mapSave, false);
+ else
{
- WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
- data << uint32(0);
- player->GetSession()->SendPacket(&data);
- player->BindToInstance(mapSave, true);
+ // cannot jump to a different instance without resetting it
+ if(groupBind->save != mapSave)
+ {
+ sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d but he is in group %d which is bound to instance %d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), GUID_LOPART(pGroup->GetLeaderGUID()), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty());
+ if(mapSave)
+ sLog.outError("MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount());
+ else
+ sLog.outError("MapSave NULL");
+ if(groupBind->save)
+ sLog.outError("GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
+ else
+ sLog.outError("GroupBind save NULL");
+ assert(false);
+ }
+ // if the group/leader is permanently bound to the instance
+ // players also become permanently bound when they enter
+ if(groupBind->perm)
+ {
+ WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
+ data << uint32(0);
+ player->GetSession()->SendPacket(&data);
+ player->BindToInstance(mapSave, true);
+ }
}
}
- }
- else
- {
- // set up a solo bind or continue using it
- if(!playerBind)
- player->BindToInstance(mapSave, false);
else
- // cannot jump to a different instance without resetting it
- assert(playerBind->save == mapSave);
+ {
+ // set up a solo bind or continue using it
+ if(!playerBind)
+ player->BindToInstance(mapSave, false);
+ else
+ // cannot jump to a different instance without resetting it
+ assert(playerBind->save == mapSave);
+ }
}
}
@@ -1948,7 +2427,6 @@ bool InstanceMap::Add(Player *player)
// first player enters (no players yet)
SetResetSchedule(false);
- player->SendInitWorldStates();
sLog.outDetail("MAP: Player '%s' entered the instance '%u' of map '%s'", player->GetName(), GetInstanceId(), GetMapName());
// initialize unload state
m_unloadTimer = 0;
@@ -2075,10 +2553,13 @@ bool InstanceMap::Reset(uint8 method)
void InstanceMap::PermBindAllPlayers(Player *player)
{
+ if(!IsDungeon())
+ return;
+
InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
if(!save)
{
- sLog.outError("Cannot bind players, no instance save available for map!\n");
+ sLog.outError("Cannot bind players, no instance save available for map!");
return;
}
@@ -2104,12 +2585,6 @@ void InstanceMap::PermBindAllPlayers(Player *player)
}
}
-time_t InstanceMap::GetResetTime()
-{
- InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
- return save ? save->GetDifficulty() : DIFFICULTY_NORMAL;
-}
-
void InstanceMap::UnloadAll()
{
if(HavePlayers())
@@ -2139,7 +2614,7 @@ void InstanceMap::SetResetSchedule(bool on)
// only for normal instances
// the reset time is only scheduled when there are no payers inside
// it is assumed that the reset time will rarely (if ever) change while the reset is scheduled
- if(!HavePlayers() && !IsRaid() && !IsHeroic())
+ if(IsDungeon() && !HavePlayers() && !IsRaid() && !IsHeroic())
{
InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
if(!save) sLog.outError("InstanceMap::SetResetSchedule: cannot turn schedule %s, no save available for instance %d of %d", on ? "on" : "off", GetInstanceId(), GetId());
@@ -2147,6 +2622,14 @@ void InstanceMap::SetResetSchedule(bool on)
}
}
+uint32 InstanceMap::GetMaxPlayers() const
+{
+ InstanceTemplate const* iTemplate = objmgr.GetInstanceTemplate(GetId());
+ if(!iTemplate)
+ return 0;
+ return IsHeroic() ? iTemplate->maxPlayersHeroic : iTemplate->maxPlayers;
+}
+
/* ******* Battleground Instance Maps ******* */
BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId)
@@ -2204,7 +2687,7 @@ void BattleGroundMap::UnloadAll()
{
if(Player * plr = m_mapRefManager.getFirst()->getSource())
{
- plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
+ plr->TeleportTo(plr->GetBattleGroundEntryPoint());
// TeleportTo removes the player from this map (if the map exists) -> calls BattleGroundMap::Remove -> invalidates the iterator.
// just in case, remove the player from the list explicitly here as well to prevent a possible infinite loop
// note that this remove is not needed if the code works well in other places