mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-15 10:00:28 +00:00
fix(Core/Movement): (#7008)
- Get zone/area IDs from vmap data in the liquid update - Add new method Map::getFullVMapDataForPosition to get area info and liquid info in a single vmap lookup - Adjust GetZoneId/GetAreaId on WorldObject to always return these cached fields. - Clean up liquid state handling on Unit and Player - Implemented getting area id from gameobject spawns. - Removed old core related to getting movement flags dependent on environment. - Movement flags are now processed more precisely and dynamically. Original source: TrinityCore. - Closes #5086 - Updates #2208.
This commit is contained in:
@@ -43,6 +43,9 @@ u_map_magic MapAreaMagic = { {'A', 'R', 'E', 'A'} };
|
||||
u_map_magic MapHeightMagic = { {'M', 'H', 'G', 'T'} };
|
||||
u_map_magic MapLiquidMagic = { {'M', 'L', 'I', 'Q'} };
|
||||
|
||||
static uint16 const holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 };
|
||||
static uint16 const holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 };
|
||||
|
||||
Map::~Map()
|
||||
{
|
||||
// UnloadAll must be called before deleting the map
|
||||
@@ -980,7 +983,7 @@ void Map::PlayerRelocation(Player* player, float x, float y, float z, float o)
|
||||
player->Relocate(x, y, z, o);
|
||||
if (player->IsVehicle())
|
||||
player->GetVehicleKit()->RelocatePassengers();
|
||||
|
||||
player->UpdatePositionData();
|
||||
player->UpdateObjectVisibility(false);
|
||||
}
|
||||
|
||||
@@ -1002,7 +1005,7 @@ void Map::CreatureRelocation(Creature* creature, float x, float y, float z, floa
|
||||
creature->Relocate(x, y, z, o);
|
||||
if (creature->IsVehicle())
|
||||
creature->GetVehicleKit()->RelocatePassengers();
|
||||
|
||||
creature->UpdatePositionData();
|
||||
creature->UpdateObjectVisibility(false);
|
||||
}
|
||||
|
||||
@@ -1023,7 +1026,7 @@ void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float
|
||||
|
||||
go->Relocate(x, y, z, o);
|
||||
go->UpdateModelPosition();
|
||||
|
||||
go->SetPositionDataUpdate();
|
||||
go->UpdateObjectVisibility(false);
|
||||
}
|
||||
|
||||
@@ -1043,7 +1046,7 @@ void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float
|
||||
RemoveDynamicObjectFromMoveList(dynObj);
|
||||
|
||||
dynObj->Relocate(x, y, z, o);
|
||||
|
||||
dynObj->SetPositionDataUpdate();
|
||||
dynObj->UpdateObjectVisibility(false);
|
||||
}
|
||||
|
||||
@@ -1307,6 +1310,7 @@ GridMap::GridMap()
|
||||
_liquidEntry = nullptr;
|
||||
_liquidFlags = nullptr;
|
||||
_liquidMap = nullptr;
|
||||
_holes = nullptr;
|
||||
}
|
||||
|
||||
GridMap::~GridMap()
|
||||
@@ -1354,6 +1358,13 @@ bool GridMap::loadData(char* filename)
|
||||
fclose(in);
|
||||
return false;
|
||||
}
|
||||
// loadup holes data (if any. check header.holesOffset)
|
||||
if (header.holesSize && !loadHolesData(in, header.holesOffset, header.holesSize))
|
||||
{
|
||||
LOG_ERROR("maps", "Error loading map holes data\n");
|
||||
fclose(in);
|
||||
return false;
|
||||
}
|
||||
fclose(in);
|
||||
return true;
|
||||
}
|
||||
@@ -1372,6 +1383,7 @@ void GridMap::unloadData()
|
||||
delete[] _liquidEntry;
|
||||
delete[] _liquidFlags;
|
||||
delete[] _liquidMap;
|
||||
delete[] _holes;
|
||||
_areaMap = nullptr;
|
||||
m_V9 = nullptr;
|
||||
m_V8 = nullptr;
|
||||
@@ -1380,6 +1392,7 @@ void GridMap::unloadData()
|
||||
_liquidEntry = nullptr;
|
||||
_liquidFlags = nullptr;
|
||||
_liquidMap = nullptr;
|
||||
_holes = nullptr;
|
||||
_gridGetHeight = &GridMap::getHeightFromFlat;
|
||||
}
|
||||
|
||||
@@ -1491,6 +1504,18 @@ bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GridMap::loadHolesData(FILE* in, uint32 offset, uint32 /*size*/)
|
||||
{
|
||||
if (fseek(in, offset, SEEK_SET) != 0)
|
||||
return false;
|
||||
|
||||
_holes = new uint16[16 * 16];
|
||||
if (fread(_holes, sizeof(uint16), 16 * 16, in) != 16 * 16)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 GridMap::getArea(float x, float y) const
|
||||
{
|
||||
if (!_areaMap)
|
||||
@@ -1523,6 +1548,9 @@ float GridMap::getHeightFromFloat(float x, float y) const
|
||||
x_int &= (MAP_RESOLUTION - 1);
|
||||
y_int &= (MAP_RESOLUTION - 1);
|
||||
|
||||
if (isHole(x_int, y_int))
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
// Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
|
||||
// +--------------> X
|
||||
// | h1-------h2 Coordinates is:
|
||||
@@ -1605,6 +1633,9 @@ float GridMap::getHeightFromUint8(float x, float y) const
|
||||
x_int &= (MAP_RESOLUTION - 1);
|
||||
y_int &= (MAP_RESOLUTION - 1);
|
||||
|
||||
if (isHole(x_int, y_int))
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
int32 a, b, c;
|
||||
uint8* V9_h1_ptr = &m_uint8_V9[x_int * 128 + x_int + y_int];
|
||||
if (x + y < 1)
|
||||
@@ -1672,6 +1703,9 @@ float GridMap::getHeightFromUint16(float x, float y) const
|
||||
x_int &= (MAP_RESOLUTION - 1);
|
||||
y_int &= (MAP_RESOLUTION - 1);
|
||||
|
||||
if (isHole(x_int, y_int))
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
int32 a, b, c;
|
||||
uint16* V9_h1_ptr = &m_uint16_V9[x_int * 128 + x_int + y_int];
|
||||
if (x + y < 1)
|
||||
@@ -1724,6 +1758,21 @@ float GridMap::getHeightFromUint16(float x, float y) const
|
||||
return (float)((a * x) + (b * y) + c) * _gridIntHeightMultiplier + _gridHeight;
|
||||
}
|
||||
|
||||
bool GridMap::isHole(int row, int col) const
|
||||
{
|
||||
if (!_holes)
|
||||
return false;
|
||||
|
||||
int cellRow = row / 8; // 8 squares per cell
|
||||
int cellCol = col / 8;
|
||||
int holeRow = row % 8 / 2;
|
||||
int holeCol = (col - (cellCol * 8)) / 2;
|
||||
|
||||
uint16 hole = _holes[cellRow * 16 + cellCol];
|
||||
|
||||
return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0;
|
||||
}
|
||||
|
||||
float GridMap::getMinHeight(float x, float y) const
|
||||
{
|
||||
if (!_minHeight)
|
||||
@@ -1803,113 +1852,96 @@ float GridMap::getLiquidLevel(float x, float y) const
|
||||
return _liquidMap[cx_int * _liquidWidth + cy_int];
|
||||
}
|
||||
|
||||
// Why does this return LIQUID data?
|
||||
uint8 GridMap::getTerrainType(float x, float y) const
|
||||
{
|
||||
if (!_liquidFlags)
|
||||
return 0;
|
||||
|
||||
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 _liquidFlags[lx * 16 + ly];
|
||||
}
|
||||
|
||||
// Get water state on map
|
||||
inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, float collisionHeight, LiquidData* data)
|
||||
inline LiquidData const GridMap::GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const
|
||||
{
|
||||
LiquidData liquidData;
|
||||
|
||||
// Check water type (if no water return)
|
||||
if (!_liquidType && !_liquidFlags)
|
||||
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
|
||||
int idx = (x_int >> 3) * 16 + (y_int >> 3);
|
||||
uint8 type = _liquidFlags ? _liquidFlags[idx] : _liquidType;
|
||||
uint32 entry = 0;
|
||||
if (_liquidEntry)
|
||||
if (_liquidType || _liquidFlags)
|
||||
{
|
||||
if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(_liquidEntry[idx]))
|
||||
{
|
||||
entry = liquidEntry->Id;
|
||||
type &= MAP_LIQUID_TYPE_DARK_WATER;
|
||||
uint32 liqTypeIdx = liquidEntry->Type;
|
||||
if (entry < 21)
|
||||
{
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
|
||||
{
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
area = sAreaTableStore.LookupEntry(area->zone);
|
||||
if (area)
|
||||
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
}
|
||||
// Get cell
|
||||
float cx = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
||||
float cy = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
||||
|
||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||
int x_int = (int) cx & (MAP_RESOLUTION - 1);
|
||||
int y_int = (int) cy & (MAP_RESOLUTION - 1);
|
||||
|
||||
// Check water type in cell
|
||||
int idx = (x_int >> 3) * 16 + (y_int >> 3);
|
||||
uint8 type = _liquidFlags ? _liquidFlags[idx] : _liquidType;
|
||||
uint32 entry = 0;
|
||||
if (_liquidEntry)
|
||||
{
|
||||
if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(_liquidEntry[idx]))
|
||||
{
|
||||
entry = liquidEntry->Id;
|
||||
type &= MAP_LIQUID_TYPE_DARK_WATER;
|
||||
uint32 liqTypeIdx = liquidEntry->Type;
|
||||
if (entry < 21)
|
||||
{
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
|
||||
{
|
||||
entry = overrideLiquid;
|
||||
liqTypeIdx = liq->Type;
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
area = sAreaTableStore.LookupEntry(area->zone);
|
||||
if (area)
|
||||
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
}
|
||||
|
||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||
{
|
||||
entry = overrideLiquid;
|
||||
liqTypeIdx = liq->Type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type |= 1 << liqTypeIdx;
|
||||
type |= 1 << liqTypeIdx;
|
||||
}
|
||||
}
|
||||
|
||||
// Check req liquid type mask
|
||||
if (type != 0 && (!ReqLiquidType || (ReqLiquidType & type) != 0))
|
||||
{
|
||||
// Check water level:
|
||||
// Check water height map
|
||||
int lx_int = x_int - _liquidOffY;
|
||||
int ly_int = y_int - _liquidOffX;
|
||||
if (lx_int >= 0 && lx_int < _liquidHeight && ly_int >= 0 && ly_int < _liquidWidth)
|
||||
{
|
||||
// Get water level
|
||||
float liquid_level = _liquidMap ? _liquidMap[lx_int * _liquidWidth + ly_int] : _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)
|
||||
{
|
||||
// All ok in water -> store data
|
||||
liquidData.Entry = entry;
|
||||
liquidData.Flags = type;
|
||||
liquidData.Level = liquid_level;
|
||||
liquidData.DepthLevel = ground_level;
|
||||
|
||||
// For speed check as int values
|
||||
float delta = liquid_level - z;
|
||||
|
||||
if (delta > collisionHeight)
|
||||
liquidData.Status = LIQUID_MAP_UNDER_WATER;
|
||||
else if (delta > 0.2f)
|
||||
liquidData.Status = LIQUID_MAP_IN_WATER;
|
||||
else if (delta > -0.2f)
|
||||
liquidData.Status = LIQUID_MAP_WATER_WALK;
|
||||
else
|
||||
liquidData.Status = LIQUID_MAP_ABOVE_WATER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 - _liquidOffY;
|
||||
int ly_int = y_int - _liquidOffX;
|
||||
if (lx_int < 0 || lx_int >= _liquidHeight)
|
||||
return LIQUID_MAP_NO_WATER;
|
||||
if (ly_int < 0 || ly_int >= _liquidWidth)
|
||||
return LIQUID_MAP_NO_WATER;
|
||||
|
||||
// Get water level
|
||||
float liquid_level = _liquidMap ? _liquidMap[lx_int * _liquidWidth + ly_int] : _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->entry = entry;
|
||||
data->type_flags = type;
|
||||
data->level = liquid_level;
|
||||
data->depth_level = ground_level;
|
||||
}
|
||||
|
||||
// For speed check as int values
|
||||
float delta = liquid_level - z;
|
||||
|
||||
if (delta > collisionHeight) // Under water
|
||||
return LIQUID_MAP_UNDER_WATER;
|
||||
if (delta > 0.0f) // In water
|
||||
return LIQUID_MAP_IN_WATER;
|
||||
if (delta > -0.1f) // Walk on water
|
||||
return LIQUID_MAP_WATER_WALK;
|
||||
// Above water
|
||||
return LIQUID_MAP_ABOVE_WATER;
|
||||
return liquidData;
|
||||
}
|
||||
|
||||
GridMap* Map::GetGrid(float x, float y)
|
||||
@@ -1933,17 +1965,15 @@ float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, fl
|
||||
if (ground)
|
||||
*ground = ground_z;
|
||||
|
||||
LiquidData liquid_status;
|
||||
|
||||
ZLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status, collisionHeight);
|
||||
switch (res)
|
||||
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, MAP_ALL_LIQUIDS);
|
||||
switch (liquidData.Status)
|
||||
{
|
||||
case LIQUID_MAP_ABOVE_WATER:
|
||||
return std::max<float>(liquid_status.level, ground_z);
|
||||
return std::max<float>(liquidData.Level, ground_z);
|
||||
case LIQUID_MAP_NO_WATER:
|
||||
return ground_z;
|
||||
default:
|
||||
return liquid_status.level;
|
||||
return liquidData.Level;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2030,115 +2060,99 @@ float Map::GetMinHeight(float x, float y) const
|
||||
return -500.0f;
|
||||
}
|
||||
|
||||
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)
|
||||
static inline bool IsInWMOInterior(uint32 mogpFlags)
|
||||
{
|
||||
bool outdoor = true;
|
||||
|
||||
if (wmoEntry && atEntry)
|
||||
{
|
||||
if (atEntry->flags & AREA_FLAG_OUTSIDE)
|
||||
return true;
|
||||
if (atEntry->flags & AREA_FLAG_INSIDE)
|
||||
return false;
|
||||
}
|
||||
|
||||
outdoor = mogpFlags & 0x8;
|
||||
|
||||
if (wmoEntry)
|
||||
{
|
||||
if (wmoEntry->Flags & 4)
|
||||
return true;
|
||||
if ((wmoEntry->Flags & 2) != 0)
|
||||
outdoor = false;
|
||||
}
|
||||
return outdoor;
|
||||
return (mogpFlags & 0x2000) != 0;
|
||||
}
|
||||
|
||||
bool Map::IsOutdoors(float x, float y, float z) const
|
||||
{
|
||||
uint32 mogpFlags;
|
||||
int32 adtId, rootId, groupId;
|
||||
|
||||
// no wmo found? -> outside by default
|
||||
if (!GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId))
|
||||
return true;
|
||||
|
||||
AreaTableEntry const* atEntry = 0;
|
||||
WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
||||
if (wmoEntry)
|
||||
{
|
||||
LOG_DEBUG("maps", "Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId);
|
||||
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
|
||||
}
|
||||
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
||||
}
|
||||
|
||||
bool Map::GetAreaInfo(float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
||||
bool Map::GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
||||
{
|
||||
float vmap_z = z;
|
||||
float dynamic_z = z;
|
||||
float check_z = z;
|
||||
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||
if (vmgr->GetAreaInfo(GetId(), x, y, vmap_z, flags, adtId, rootId, groupId))
|
||||
uint32 vflags;
|
||||
int32 vadtId;
|
||||
int32 vrootId;
|
||||
int32 vgroupId;
|
||||
uint32 dflags;
|
||||
int32 dadtId;
|
||||
int32 drootId;
|
||||
int32 dgroupId;
|
||||
|
||||
bool hasVmapAreaInfo = vmgr->GetAreaInfo(GetId(), x, y, vmap_z, vflags, vadtId, vrootId, vgroupId);
|
||||
bool hasDynamicAreaInfo = _dynamicTree.GetAreaInfo(x, y, dynamic_z, phaseMask, dflags, dadtId, drootId, dgroupId);
|
||||
auto useVmap = [&]() { check_z = vmap_z; flags = vflags; adtId = vadtId; rootId = vrootId; groupId = vgroupId; };
|
||||
auto useDyn = [&]() { check_z = dynamic_z; flags = dflags; adtId = dadtId; rootId = drootId; groupId = dgroupId; };
|
||||
|
||||
if (hasVmapAreaInfo)
|
||||
{
|
||||
if (hasDynamicAreaInfo && dynamic_z > vmap_z)
|
||||
useDyn();
|
||||
else
|
||||
useVmap();
|
||||
}
|
||||
else if (hasDynamicAreaInfo)
|
||||
{
|
||||
useDyn();
|
||||
}
|
||||
|
||||
if (hasVmapAreaInfo || hasDynamicAreaInfo)
|
||||
{
|
||||
// check if there's terrain between player height and object height
|
||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
{
|
||||
float _mapheight = gmap->getHeight(x, y);
|
||||
float mapHeight = gmap->getHeight(x, y);
|
||||
// z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice...
|
||||
if (z + 2.0f > _mapheight && _mapheight > vmap_z)
|
||||
if (z + 2.0f > mapHeight && mapHeight > check_z)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 Map::GetAreaId(float x, float y, float z, bool* isOutdoors) const
|
||||
uint32 Map::GetAreaId(uint32 phaseMask, float x, float y, float z) const
|
||||
{
|
||||
uint32 mogpFlags;
|
||||
int32 adtId, rootId, groupId;
|
||||
WMOAreaTableEntry const* wmoEntry = 0;
|
||||
AreaTableEntry const* atEntry = 0;
|
||||
bool haveAreaInfo = false;
|
||||
float vmapZ = 0.f;
|
||||
bool hasVmapArea = GetAreaInfo(phaseMask, x, y, vmapZ, mogpFlags, adtId, rootId, groupId);
|
||||
|
||||
if (GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId))
|
||||
uint32 gridAreaId = 0;
|
||||
float gridMapHeight = INVALID_HEIGHT;
|
||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
{
|
||||
haveAreaInfo = true;
|
||||
wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
||||
if (wmoEntry)
|
||||
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
|
||||
gridAreaId = gmap->getArea(x, y);
|
||||
gridMapHeight = gmap->getHeight(x, y);
|
||||
}
|
||||
|
||||
uint16 areaId = 0;
|
||||
|
||||
if (atEntry)
|
||||
areaId = atEntry->ID;
|
||||
else
|
||||
// floor is the height we are closer to (but only if above)
|
||||
if (hasVmapArea && G3D::fuzzyGe(z, vmapZ - GROUND_HEIGHT_TOLERANCE) && (G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || vmapZ > gridMapHeight))
|
||||
{
|
||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
areaId = gmap->getArea(x, y);
|
||||
// this used while not all *.map files generated (instances)
|
||||
if (!areaId)
|
||||
areaId = i_mapEntry->linked_zone;
|
||||
}
|
||||
// wmo found
|
||||
if (WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId))
|
||||
areaId = wmoEntry->areaId;
|
||||
|
||||
if (isOutdoors)
|
||||
{
|
||||
if (haveAreaInfo)
|
||||
*isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
||||
else
|
||||
*isOutdoors = true;
|
||||
if (!areaId)
|
||||
areaId = gridAreaId;
|
||||
}
|
||||
else
|
||||
areaId = gridAreaId;
|
||||
|
||||
if (!areaId)
|
||||
areaId = i_mapEntry->linked_zone;
|
||||
|
||||
return areaId;
|
||||
}
|
||||
|
||||
uint32 Map::GetAreaId(float x, float y, float z) const
|
||||
uint32 Map::GetZoneId(uint32 phaseMask, float x, float y, float z) const
|
||||
{
|
||||
return GetAreaId(x, y, z, nullptr);
|
||||
}
|
||||
|
||||
uint32 Map::GetZoneId(float x, float y, float z) const
|
||||
{
|
||||
uint32 areaId = GetAreaId(x, y, z);
|
||||
uint32 areaId = GetAreaId(phaseMask, x, y, z);
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
|
||||
if (area->zone)
|
||||
return area->zone;
|
||||
@@ -2146,105 +2160,239 @@ uint32 Map::GetZoneId(float x, float y, float z) const
|
||||
return areaId;
|
||||
}
|
||||
|
||||
void Map::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
|
||||
void Map::GetZoneAndAreaId(uint32 phaseMask, uint32& zoneid, uint32& areaid, float x, float y, float z) const
|
||||
{
|
||||
areaid = zoneid = GetAreaId(x, y, z);
|
||||
areaid = zoneid = GetAreaId(phaseMask, x, y, z);
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid))
|
||||
if (area->zone)
|
||||
zoneid = area->zone;
|
||||
}
|
||||
|
||||
uint8 Map::GetTerrainType(float x, float y) const
|
||||
LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, uint8 ReqLiquidType)
|
||||
{
|
||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
return gmap->getTerrainType(x, y);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
LiquidData liquidData;
|
||||
|
||||
ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data, float collisionHeight) const
|
||||
{
|
||||
ZLiquidStatus result = LIQUID_MAP_NO_WATER;
|
||||
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||
float liquid_level = INVALID_HEIGHT;
|
||||
float ground_level = INVALID_HEIGHT;
|
||||
uint32 liquid_type = 0;
|
||||
if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type))
|
||||
uint32 mogpFlags = 0;
|
||||
bool useGridLiquid = true;
|
||||
if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type, mogpFlags))
|
||||
{
|
||||
LOG_DEBUG("maps", "getLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type);
|
||||
useGridLiquid = !IsInWMOInterior(mogpFlags);
|
||||
LOG_DEBUG("maps", "GetLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type);
|
||||
// Check water level and ground level
|
||||
if (liquid_level > ground_level && z > ground_level - 2)
|
||||
if (liquid_level > ground_level && G3D::fuzzyGe(z, ground_level - GROUND_HEIGHT_TOLERANCE))
|
||||
{
|
||||
// All ok in water -> store data
|
||||
if (data)
|
||||
// hardcoded in client like this
|
||||
if (GetId() == 530 && liquid_type == 2)
|
||||
liquid_type = 15;
|
||||
|
||||
uint32 liquidFlagType = 0;
|
||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquid_type))
|
||||
liquidFlagType = liq->Type;
|
||||
|
||||
if (liquid_type && liquid_type < 21)
|
||||
{
|
||||
// hardcoded in client like this
|
||||
if (GetId() == 530 && liquid_type == 2)
|
||||
liquid_type = 15;
|
||||
|
||||
uint32 liquidFlagType = 0;
|
||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquid_type))
|
||||
liquidFlagType = liq->Type;
|
||||
|
||||
if (liquid_type && liquid_type < 21)
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(phaseMask, x, y, z)))
|
||||
{
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(x, y, z)))
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
area = sAreaTableStore.LookupEntry(area->zone);
|
||||
if (area)
|
||||
overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||
}
|
||||
area = sAreaTableStore.LookupEntry(area->zone);
|
||||
if (area)
|
||||
overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||
}
|
||||
|
||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||
{
|
||||
liquid_type = overrideLiquid;
|
||||
liquidFlagType = liq->Type;
|
||||
}
|
||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||
{
|
||||
liquid_type = overrideLiquid;
|
||||
liquidFlagType = liq->Type;
|
||||
}
|
||||
}
|
||||
|
||||
data->level = liquid_level;
|
||||
data->depth_level = ground_level;
|
||||
|
||||
data->entry = liquid_type;
|
||||
data->type_flags = 1 << liquidFlagType;
|
||||
}
|
||||
|
||||
float delta = liquid_level - z;
|
||||
|
||||
// Get position delta
|
||||
if (delta > collisionHeight) // Under water
|
||||
return LIQUID_MAP_UNDER_WATER;
|
||||
if (delta > 0.0f) // In water
|
||||
return LIQUID_MAP_IN_WATER;
|
||||
if (delta > -0.1f) // Walk on water
|
||||
return LIQUID_MAP_WATER_WALK;
|
||||
result = LIQUID_MAP_ABOVE_WATER;
|
||||
liquidData.Level = liquid_level;
|
||||
liquidData.DepthLevel = ground_level;
|
||||
liquidData.Entry = liquid_type;
|
||||
liquidData.Flags = 1 << liquidFlagType;
|
||||
}
|
||||
|
||||
float delta = liquid_level - z;
|
||||
|
||||
// Get position delta
|
||||
if (delta > collisionHeight)
|
||||
liquidData.Status = LIQUID_MAP_UNDER_WATER;
|
||||
if (delta > 0.2f)
|
||||
liquidData.Status = LIQUID_MAP_IN_WATER;
|
||||
if (delta > -0.2f)
|
||||
liquidData.Status = LIQUID_MAP_WATER_WALK;
|
||||
else
|
||||
liquidData.Status = LIQUID_MAP_ABOVE_WATER;
|
||||
}
|
||||
|
||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
if (useGridLiquid)
|
||||
{
|
||||
LiquidData map_data;
|
||||
ZLiquidStatus map_result = gmap->getLiquidStatus(x, y, z, ReqLiquidType, collisionHeight, &map_data);
|
||||
// Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
|
||||
if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > ground_level))
|
||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
{
|
||||
if (data)
|
||||
LiquidData const& map_data = gmap->GetLiquidData(x, y, z, collisionHeight, ReqLiquidType);
|
||||
// Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
|
||||
if (map_data.Status != LIQUID_MAP_NO_WATER && (map_data.Level > ground_level))
|
||||
{
|
||||
// hardcoded in client like this
|
||||
if (GetId() == 530 && map_data.entry == 2)
|
||||
map_data.entry = 15;
|
||||
uint32 liquidEntry = map_data.Entry;
|
||||
if (GetId() == 530 && liquidEntry == 2)
|
||||
liquidEntry = 15;
|
||||
|
||||
*data = map_data;
|
||||
liquidData = map_data;
|
||||
liquidData.Entry = liquidEntry;
|
||||
}
|
||||
return map_result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
return liquidData;
|
||||
}
|
||||
|
||||
void Map::GetFullTerrainStatusForPosition(uint32 phaseMask, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, uint8 reqLiquidType)
|
||||
{
|
||||
GridMap* gmap = GetGrid(x, y);
|
||||
|
||||
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||
VMAP::AreaAndLiquidData vmapData;
|
||||
VMAP::AreaAndLiquidData dynData;
|
||||
VMAP::AreaAndLiquidData* wmoData = nullptr;
|
||||
vmgr->GetAreaAndLiquidData(GetId(), x, y, z, reqLiquidType, vmapData);
|
||||
_dynamicTree.GetAreaAndLiquidData(x, y, z, phaseMask, reqLiquidType, dynData);
|
||||
|
||||
uint32 gridAreaId = 0;
|
||||
float gridMapHeight = INVALID_HEIGHT;
|
||||
if (gmap)
|
||||
{
|
||||
gridAreaId = gmap->getArea(x, y);
|
||||
gridMapHeight = gmap->getHeight(x, y);
|
||||
}
|
||||
|
||||
bool useGridLiquid = true;
|
||||
|
||||
// floor is the height we are closer to (but only if above)
|
||||
data.floorZ = VMAP_INVALID_HEIGHT;
|
||||
if (gridMapHeight > INVALID_HEIGHT && G3D::fuzzyGe(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE))
|
||||
data.floorZ = gridMapHeight;
|
||||
|
||||
if (vmapData.floorZ > VMAP_INVALID_HEIGHT && G3D::fuzzyGe(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE) &&
|
||||
(G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || vmapData.floorZ > gridMapHeight))
|
||||
{
|
||||
data.floorZ = vmapData.floorZ;
|
||||
wmoData = &vmapData;
|
||||
}
|
||||
|
||||
// NOTE: Objects will not detect a case when a wmo providing area/liquid despawns from under them
|
||||
// but this is fine as these kind of objects are not meant to be spawned and despawned a lot
|
||||
// example: Lich King platform
|
||||
if (dynData.floorZ > VMAP_INVALID_HEIGHT && G3D::fuzzyGe(z, dynData.floorZ - GROUND_HEIGHT_TOLERANCE) &&
|
||||
(G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || dynData.floorZ > gridMapHeight) &&
|
||||
(G3D::fuzzyLt(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE) || dynData.floorZ > vmapData.floorZ))
|
||||
{
|
||||
data.floorZ = dynData.floorZ;
|
||||
wmoData = &dynData;
|
||||
}
|
||||
|
||||
if (wmoData)
|
||||
{
|
||||
if (wmoData->areaInfo)
|
||||
{
|
||||
// wmo found
|
||||
WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(wmoData->areaInfo->rootId, wmoData->areaInfo->adtId, wmoData->areaInfo->groupId);
|
||||
data.outdoors = (wmoData->areaInfo->mogpFlags & 0x8) != 0;
|
||||
if (wmoEntry)
|
||||
{
|
||||
data.areaId = wmoEntry->areaId;
|
||||
if (wmoEntry->Flags & 4)
|
||||
data.outdoors = true;
|
||||
else if (wmoEntry->Flags & 2)
|
||||
data.outdoors = false;
|
||||
}
|
||||
|
||||
if (!data.areaId)
|
||||
data.areaId = gridAreaId;
|
||||
|
||||
useGridLiquid = !IsInWMOInterior(wmoData->areaInfo->mogpFlags);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data.outdoors = true;
|
||||
data.areaId = gridAreaId;
|
||||
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId))
|
||||
data.outdoors = (areaEntry->flags & (AREA_FLAG_INSIDE | AREA_FLAG_OUTSIDE)) != AREA_FLAG_INSIDE;
|
||||
}
|
||||
|
||||
if (!data.areaId)
|
||||
data.areaId = i_mapEntry->linked_zone;
|
||||
|
||||
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId);
|
||||
|
||||
// liquid processing
|
||||
if (wmoData && wmoData->liquidInfo && wmoData->liquidInfo->level > wmoData->floorZ)
|
||||
{
|
||||
uint32 liquidType = wmoData->liquidInfo->type;
|
||||
if (GetId() == 530 && liquidType == 2) // gotta love blizzard hacks
|
||||
liquidType = 15;
|
||||
|
||||
uint32 liquidFlagType = 0;
|
||||
if (LiquidTypeEntry const* liquidData = sLiquidTypeStore.LookupEntry(liquidType))
|
||||
liquidFlagType = liquidData->Type;
|
||||
|
||||
if (liquidType && liquidType < 21 && areaEntry)
|
||||
{
|
||||
uint32 overrideLiquid = areaEntry->LiquidTypeOverride[liquidFlagType];
|
||||
if (!overrideLiquid && areaEntry->zone)
|
||||
{
|
||||
AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(areaEntry->zone);
|
||||
if (zoneEntry)
|
||||
overrideLiquid = zoneEntry->LiquidTypeOverride[liquidFlagType];
|
||||
}
|
||||
|
||||
if (LiquidTypeEntry const* overrideData = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||
{
|
||||
liquidType = overrideLiquid;
|
||||
liquidFlagType = overrideData->Type;
|
||||
}
|
||||
}
|
||||
|
||||
data.liquidInfo.Level = wmoData->liquidInfo->level;
|
||||
data.liquidInfo.DepthLevel = wmoData->floorZ;
|
||||
data.liquidInfo.Entry = liquidType;
|
||||
data.liquidInfo.Flags = 1 << liquidFlagType;
|
||||
|
||||
// Get position delta
|
||||
float delta = wmoData->liquidInfo->level - z;
|
||||
|
||||
if (delta > collisionHeight)
|
||||
data.liquidInfo.Status = LIQUID_MAP_UNDER_WATER;
|
||||
else if (delta > 0.2f)
|
||||
data.liquidInfo.Status = LIQUID_MAP_IN_WATER;
|
||||
else if (delta > -0.2f)
|
||||
data.liquidInfo.Status = LIQUID_MAP_WATER_WALK;
|
||||
else
|
||||
data.liquidInfo.Status = LIQUID_MAP_ABOVE_WATER;
|
||||
}
|
||||
|
||||
// look up liquid data from grid map
|
||||
if (gmap && useGridLiquid)
|
||||
{
|
||||
LiquidData const& gridLiquidData = gmap->GetLiquidData(x, y, z, collisionHeight, reqLiquidType);
|
||||
if (gridLiquidData.Status != LIQUID_MAP_NO_WATER && (!wmoData || gridLiquidData.Level > wmoData->floorZ))
|
||||
{
|
||||
uint32 liquidEntry = gridLiquidData.Entry;
|
||||
if (GetId() == 530 && liquidEntry == 2)
|
||||
liquidEntry = 15;
|
||||
|
||||
data.liquidInfo = gridLiquidData;
|
||||
data.liquidInfo.Entry = liquidEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float Map::GetWaterLevel(float x, float y) const
|
||||
@@ -2288,30 +2436,28 @@ float Map::GetHeight(uint32 phasemask, float x, float y, float z, bool vmap/*=tr
|
||||
return std::max<float>(h1, h2);
|
||||
}
|
||||
|
||||
bool Map::IsInWater(float x, float y, float pZ, LiquidData* data) const
|
||||
bool Map::IsInWater(uint32 phaseMask, float x, float y, float pZ, float collisionHeight) const
|
||||
{
|
||||
LiquidData liquid_status;
|
||||
LiquidData* liquid_ptr = data ? data : &liquid_status;
|
||||
return getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr) & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER);
|
||||
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phaseMask, x, y, pZ, collisionHeight, MAP_ALL_LIQUIDS);
|
||||
return (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) != 0;
|
||||
}
|
||||
|
||||
bool Map::IsUnderWater(float x, float y, float z) const
|
||||
bool Map::IsUnderWater(uint32 phaseMask, float x, float y, float z, float collisionHeight) const
|
||||
{
|
||||
return getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN) & LIQUID_MAP_UNDER_WATER;
|
||||
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phaseMask, x, y, z, collisionHeight, MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN);
|
||||
return liquidData.Status == LIQUID_MAP_UNDER_WATER;
|
||||
}
|
||||
|
||||
bool Map::HasEnoughWater(WorldObject const* searcher, float x, float y, float z) const
|
||||
{
|
||||
LiquidData liquidData;
|
||||
liquidData.level = INVALID_HEIGHT;
|
||||
ZLiquidStatus liquidStatus = getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData);
|
||||
return (liquidStatus & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) && HasEnoughWater(searcher, liquidData);
|
||||
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(searcher->GetPhaseMask(), x, y, z, searcher->GetCollisionHeight(), MAP_ALL_LIQUIDS);
|
||||
return (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) != 0 && HasEnoughWater(searcher, liquidData);
|
||||
}
|
||||
|
||||
bool Map::HasEnoughWater(WorldObject const* searcher, LiquidData liquidData) const
|
||||
bool Map::HasEnoughWater(WorldObject const* searcher, LiquidData const& liquidData) const
|
||||
{
|
||||
float minHeightInWater = searcher->GetMinHeightInWater();
|
||||
return liquidData.level > INVALID_HEIGHT && liquidData.level > liquidData.depth_level && liquidData.level - liquidData.depth_level >= minHeightInWater;
|
||||
return liquidData.Level > INVALID_HEIGHT && liquidData.Level > liquidData.DepthLevel && liquidData.Level - liquidData.DepthLevel >= minHeightInWater;
|
||||
}
|
||||
|
||||
char const* Map::GetMapName() const
|
||||
@@ -3421,6 +3567,8 @@ Corpse* Map::ConvertCorpseToBones(ObjectGuid const ownerGuid, bool insignia /*=
|
||||
|
||||
AddCorpse(bones);
|
||||
|
||||
bones->UpdatePositionData();
|
||||
|
||||
// add bones in grid store if grid loaded where corpse placed
|
||||
AddToMap(bones);
|
||||
}
|
||||
@@ -3459,7 +3607,7 @@ void Map::RemoveOldCorpses()
|
||||
|
||||
void Map::SendZoneDynamicInfo(Player* player)
|
||||
{
|
||||
uint32 zoneId = GetZoneId(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
|
||||
uint32 zoneId = player->GetZoneId();
|
||||
ZoneDynamicInfoMap::const_iterator itr = _zoneDynamicInfo.find(zoneId);
|
||||
if (itr == _zoneDynamicInfo.end())
|
||||
return;
|
||||
@@ -3671,7 +3819,7 @@ bool Map::CheckCollisionAndGetValidCoords(const WorldObject* source, float start
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isWaterNext = IsInWater(destX, destY, destZ);
|
||||
bool isWaterNext = IsInWater(source->GetPhaseMask(), destX, destY, destZ, source->GetCollisionHeight());
|
||||
|
||||
PathGenerator path(source);
|
||||
|
||||
@@ -3784,6 +3932,8 @@ void Map::LoadCorpseData()
|
||||
}
|
||||
|
||||
AddCorpse(corpse);
|
||||
|
||||
corpse->UpdatePositionData();
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user