aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Maps/Map.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Maps/Map.cpp')
-rw-r--r--src/server/game/Maps/Map.cpp116
1 files changed, 88 insertions, 28 deletions
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index e0378bfb7aa..bc23cc3ec5f 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -2446,7 +2446,7 @@ float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, fl
LiquidData liquid_status;
- ZLiquidStatus res = GetLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status, collisionHeight);
+ ZLiquidStatus res = GetLiquidStatus(phasemask, x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status, collisionHeight);
switch (res)
{
case LIQUID_MAP_ABOVE_WATER:
@@ -2518,14 +2518,61 @@ float Map::GetMinHeight(float x, float y) const
static inline bool IsInWMOInterior(uint32 mogpFlags)
{
return (mogpFlags & 0x2000) != 0;
+}
+
+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();
+ 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();
}
-uint32 Map::GetAreaId(float x, float y, float z) const
+ 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);
+ // z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice...
+ if (z + 2.0f > mapHeight && mapHeight > check_z)
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+uint32 Map::GetAreaId(uint32 phaseMask, float x, float y, float z) const
{
uint32 mogpFlags;
int32 adtId, rootId, groupId;
float vmapZ = z;
- bool hasVmapArea = VMAP::VMapFactory::createOrGetVMapManager()->getAreaInfo(GetId(), x, y, vmapZ, mogpFlags, adtId, rootId, groupId);
+ bool hasVmapArea = GetAreaInfo(phaseMask, x, y, vmapZ, mogpFlags, adtId, rootId, groupId);
uint32 gridAreaId = 0;
float gridMapHeight = INVALID_HEIGHT;
@@ -2556,9 +2603,9 @@ uint32 Map::GetAreaId(float x, float y, float z) const
return areaId;
}
-uint32 Map::GetZoneId(float x, float y, float z) const
+uint32 Map::GetZoneId(uint32 phaseMask, 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;
@@ -2566,15 +2613,15 @@ 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;
}
-ZLiquidStatus Map::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data, float collisionHeight) const
+ZLiquidStatus Map::GetLiquidStatus(uint32 phaseMask, 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();
@@ -2603,7 +2650,7 @@ ZLiquidStatus Map::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp
if (liquid_type && liquid_type < 21)
{
- if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(x, y, z)))
+ if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(phaseMask, x, y, z)))
{
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
if (!overrideLiquid && area->zone)
@@ -2665,12 +2712,15 @@ ZLiquidStatus Map::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp
return result;
}
-void Map::GetFullTerrainStatusForPosition(float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType, float collisionHeight) const
+void Map::GetFullTerrainStatusForPosition(uint32 phaseMask, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType, float collisionHeight) const
{
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
VMAP::AreaAndLiquidData vmapData;
+ VMAP::AreaAndLiquidData dynData;
+ VMAP::AreaAndLiquidData* wmoData = nullptr;
GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y);
vmgr->getAreaAndLiquidData(GetId(), x, y, z, reqLiquidType, vmapData);
+ _dynamicTree.getAreaAndLiquidData(x, y, z, phaseMask, reqLiquidType, dynData);
uint32 gridAreaId = 0;
float gridMapHeight = INVALID_HEIGHT;
@@ -2680,7 +2730,6 @@ void Map::GetFullTerrainStatusForPosition(float x, float y, float z, PositionFul
gridMapHeight = gmap->getHeight(x, y);
}
- bool vmapLocation = false;
bool useGridLiquid = true;
// floor is the height we are closer to (but only if above)
@@ -2692,17 +2741,28 @@ void Map::GetFullTerrainStatusForPosition(float x, float y, float z, PositionFul
(G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || vmapData.floorZ > gridMapHeight))
{
data.floorZ = vmapData.floorZ;
- vmapLocation = true;
+ 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 (vmapLocation)
+ if (wmoData)
{
- if (vmapData.areaInfo)
+ if (wmoData->areaInfo)
{
- data.areaInfo = boost::in_place(vmapData.areaInfo->adtId, vmapData.areaInfo->rootId, vmapData.areaInfo->groupId, vmapData.areaInfo->mogpFlags);
+ data.areaInfo = boost::in_place(wmoData->areaInfo->adtId, wmoData->areaInfo->rootId, wmoData->areaInfo->groupId, wmoData->areaInfo->mogpFlags);
// wmo found
- WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(vmapData.areaInfo->rootId, vmapData.areaInfo->adtId, vmapData.areaInfo->groupId);
- data.outdoors = (vmapData.areaInfo->mogpFlags & 0x8) != 0;
+ 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;
@@ -2715,7 +2775,7 @@ void Map::GetFullTerrainStatusForPosition(float x, float y, float z, PositionFul
if (!data.areaId)
data.areaId = gridAreaId;
- useGridLiquid = !IsInWMOInterior(vmapData.areaInfo->mogpFlags);
+ useGridLiquid = !IsInWMOInterior(wmoData->areaInfo->mogpFlags);
}
}
else
@@ -2733,9 +2793,9 @@ void Map::GetFullTerrainStatusForPosition(float x, float y, float z, PositionFul
// liquid processing
data.liquidStatus = LIQUID_MAP_NO_WATER;
- if (vmapLocation && vmapData.liquidInfo && vmapData.liquidInfo->level > vmapData.floorZ)
+ if (wmoData && wmoData->liquidInfo && wmoData->liquidInfo->level > wmoData->floorZ)
{
- uint32 liquidType = vmapData.liquidInfo->type;
+ uint32 liquidType = wmoData->liquidInfo->type;
if (GetId() == 530 && liquidType == 2) // gotta love blizzard hacks
liquidType = 15;
@@ -2761,12 +2821,12 @@ void Map::GetFullTerrainStatusForPosition(float x, float y, float z, PositionFul
}
data.liquidInfo = boost::in_place();
- data.liquidInfo->level = vmapData.liquidInfo->level;
- data.liquidInfo->depth_level = vmapData.floorZ;
+ data.liquidInfo->level = wmoData->liquidInfo->level;
+ data.liquidInfo->depth_level = wmoData->floorZ;
data.liquidInfo->entry = liquidType;
data.liquidInfo->type_flags = 1 << liquidFlagType;
- float delta = vmapData.liquidInfo->level - z;
+ float delta = wmoData->liquidInfo->level - z;
if (delta > collisionHeight)
data.liquidStatus = LIQUID_MAP_UNDER_WATER;
else if (delta > 0.0f)
@@ -2781,7 +2841,7 @@ void Map::GetFullTerrainStatusForPosition(float x, float y, float z, PositionFul
{
LiquidData gridMapLiquid;
ZLiquidStatus gridMapStatus = gmap->GetLiquidStatus(x, y, z, reqLiquidType, &gridMapLiquid, collisionHeight);
- if (gridMapStatus != LIQUID_MAP_NO_WATER && (gridMapLiquid.level > vmapData.floorZ))
+ if (gridMapStatus != LIQUID_MAP_NO_WATER && (!wmoData || gridMapLiquid.level > wmoData->floorZ))
{
if (GetId() == 530 && gridMapLiquid.entry == 2)
gridMapLiquid.entry = 15;
@@ -2824,16 +2884,16 @@ bool Map::getObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float
return result;
}
-bool Map::IsInWater(float x, float y, float pZ, LiquidData* data) const
+bool Map::IsInWater(uint32 phaseMask, float x, float y, float pZ, LiquidData* data) 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)) != 0;
+ return (GetLiquidStatus(phaseMask, x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr) & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) != 0;
}
-bool Map::IsUnderWater(float x, float y, float z) const
+bool Map::IsUnderWater(uint32 phaseMask, float x, float y, float z) const
{
- return (GetLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN) & LIQUID_MAP_UNDER_WATER) != 0;
+ return (GetLiquidStatus(phaseMask, x, y, z, MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN) & LIQUID_MAP_UNDER_WATER) != 0;
}
bool Map::CheckGridIntegrity(Creature* c, bool moved) const