diff options
-rw-r--r-- | src/common/Collision/Management/IVMapManager.h | 4 | ||||
-rw-r--r-- | src/common/Collision/Management/VMapManager2.cpp | 5 | ||||
-rw-r--r-- | src/common/Collision/Management/VMapManager2.h | 6 | ||||
-rw-r--r-- | src/common/Collision/Models/WorldModel.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 17 | ||||
-rw-r--r-- | src/server/game/Maps/Map.cpp | 305 | ||||
-rw-r--r-- | src/server/game/Maps/Map.h | 10 | ||||
-rw-r--r-- | src/server/game/Movement/PathGenerator.cpp | 3 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_druid.cpp | 2 | ||||
-rw-r--r-- | src/tools/mmaps_generator/TerrainBuilder.cpp | 2 |
10 files changed, 193 insertions, 166 deletions
diff --git a/src/common/Collision/Management/IVMapManager.h b/src/common/Collision/Management/IVMapManager.h index e779878b8e0..ec198ffcc70 100644 --- a/src/common/Collision/Management/IVMapManager.h +++ b/src/common/Collision/Management/IVMapManager.h @@ -122,8 +122,8 @@ namespace VMAP Query world model area info. \param z gets adjusted to the ground height for which this are info is valid */ - virtual bool getAreaInfo(unsigned int pMapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const=0; - virtual bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float &level, float &floor, uint32 &type) const=0; + virtual bool getAreaInfo(uint32 mapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const=0; + virtual bool GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const=0; // get both area + liquid data in a single vmap lookup virtual void getAreaAndLiquidData(unsigned int mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const=0; }; diff --git a/src/common/Collision/Management/VMapManager2.cpp b/src/common/Collision/Management/VMapManager2.cpp index 3a45a12e556..d235b458681 100644 --- a/src/common/Collision/Management/VMapManager2.cpp +++ b/src/common/Collision/Management/VMapManager2.cpp @@ -286,7 +286,7 @@ namespace VMAP return VMAP_INVALID_HEIGHT_VALUE; } - bool VMapManager2::getAreaInfo(unsigned int mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const + bool VMapManager2::getAreaInfo(uint32 mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const { if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG)) { @@ -304,7 +304,7 @@ namespace VMAP return false; } - bool VMapManager2::GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type) const + bool VMapManager2::GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const { if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS)) { @@ -319,6 +319,7 @@ namespace VMAP ASSERT(floor < std::numeric_limits<float>::max()); ASSERT(info.hitModel); type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc + mogpFlags = info.hitModel->GetMogpFlags(); if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType)) return false; ASSERT(info.hitInstance); diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h index bd039877533..64c550c48cf 100644 --- a/src/common/Collision/Management/VMapManager2.h +++ b/src/common/Collision/Management/VMapManager2.h @@ -107,9 +107,9 @@ namespace VMAP bool processCommand(char* /*command*/) override { return false; } // for debug and extensions - bool getAreaInfo(unsigned int pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const override; - bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type) const override; - void getAreaAndLiquidData(unsigned int mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const override; + bool getAreaInfo(uint32 mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const override; + bool GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const override; + void getAreaAndLiquidData(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const override; WorldModel* acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags = 0); void releaseModelInstance(const std::string& filename); diff --git a/src/common/Collision/Models/WorldModel.cpp b/src/common/Collision/Models/WorldModel.cpp index 9bbb6278950..4c0f7042b75 100644 --- a/src/common/Collision/Models/WorldModel.cpp +++ b/src/common/Collision/Models/WorldModel.cpp @@ -398,9 +398,7 @@ namespace VMAP vertices(vert.begin()), triangles(tris.begin()), hit(false) { } bool operator()(G3D::Ray const& ray, uint32 entry, float& distance, bool /*pStopAtFirstHit*/) { - bool result = IntersectTriangle(triangles[entry], vertices, ray, distance); - if (result) - hit = true; + hit = IntersectTriangle(triangles[entry], vertices, ray, distance) || hit; return hit; } std::vector<Vector3>::const_iterator vertices; @@ -422,7 +420,6 @@ namespace VMAP { if (triangles.empty() || !iBound.contains(pos)) return false; - GModelRayCallback callback(triangles, vertices); Vector3 rPos = pos - 0.1f * down; float dist = G3D::finf(); G3D::Ray ray(rPos, down); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 0dea9b378d8..45a99197fbf 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -3130,9 +3130,12 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float return; } + float halfHeight = GetCollisionHeight() * 0.5f; UpdateAllowedPositionZ(destx, desty, destz); bool col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(PhasingHandler::GetTerrainMapId(GetPhaseShift(), GetMap(), pos.m_positionX, pos.m_positionY), - pos.m_positionX, pos.m_positionY, pos.m_positionZ, destx, desty, destz, destx, desty, destz, -0.5f); + pos.m_positionX, pos.m_positionY, pos.m_positionZ + halfHeight, + destx, desty, destz + halfHeight, + destx, desty, destz, -0.5f); // collision occured if (col) @@ -3144,7 +3147,10 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float } // check dynamic collision - col = GetMap()->getObjectHitPos(GetPhaseShift(), pos.m_positionX, pos.m_positionY, pos.m_positionZ, destx, desty, destz, destx, desty, destz, -0.5f); + col = GetMap()->getObjectHitPos(GetPhaseShift(), + pos.m_positionX, pos.m_positionY, pos.m_positionZ + halfHeight, + destx, desty, destz + halfHeight, + destx, desty, destz, -0.5f); // Collided with a gameobject if (col) @@ -3342,10 +3348,9 @@ float WorldObject::GetFloorZ() const float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* ground/* = nullptr*/) const { - if (Unit const* unit = ToUnit()) - return GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ground, !unit->HasAuraType(SPELL_AURA_WATER_WALK), GetCollisionHeight()); - - return z; + return GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ground, + isType(TYPEMASK_UNIT) ? !static_cast<Unit const*>(this)->HasAuraType(SPELL_AURA_WATER_WALK) : false, + GetCollisionHeight()); } float WorldObject::GetMapHeight(float x, float y, float z, bool vmap/* = true*/, float distanceToSearch/* = DEFAULT_HEIGHT_SEARCH*/) const diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 81578dbc41a..ad84dd0e38c 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -1833,6 +1833,7 @@ GridMap::GridMap() _liquidEntry = nullptr; _liquidFlags = nullptr; _liquidMap = nullptr; + _holes = nullptr; } GridMap::~GridMap() @@ -1880,6 +1881,13 @@ GridMap::LoadResult GridMap::loadData(char const* filename) fclose(in); return LoadResult::InvalidFile; } + // loadup holes data (if any. check header.holesOffset) + if (header.holesSize && !loadHolesData(in, header.holesOffset, header.holesSize)) + { + TC_LOG_ERROR("maps", "Error loading map holes data\n"); + fclose(in); + return LoadResult::InvalidFile; + } fclose(in); return LoadResult::Ok; } @@ -1899,6 +1907,7 @@ void GridMap::unloadData() delete[] _liquidEntry; delete[] _liquidFlags; delete[] _liquidMap; + delete[] _holes; _areaMap = nullptr; m_V9 = nullptr; m_V8 = nullptr; @@ -1906,6 +1915,7 @@ void GridMap::unloadData() _liquidEntry = nullptr; _liquidFlags = nullptr; _liquidMap = nullptr; + _holes = nullptr; _gridGetHeight = &GridMap::getHeightFromFlat; } @@ -2051,6 +2061,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 uint8[16 * 16 * 8]; + if (fread(_holes, sizeof(uint8), 16 * 16 * 8, in) != 16 * 16 * 8) + return false; + + return true; +} + uint16 GridMap::getArea(float x, float y) const { if (!_areaMap) @@ -2083,6 +2105,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: @@ -2165,6 +2190,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) @@ -2232,6 +2260,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) @@ -2284,6 +2315,19 @@ 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; + int holeCol = col % 8; + + return (_holes[cellRow * 16 * 8 + cellCol * 8 + holeRow] & (1 << holeCol)) != 0; +} + float GridMap::getMinHeight(float x, float y) const { if (!_minHeightPlanes) @@ -2333,19 +2377,6 @@ float GridMap::getLiquidLevel(float x, float y) const return _liquidMap[cx_int*_liquidWidth + cy_int]; } -// Why does this return LIQUID data? -map_liquidHeaderTypeFlags GridMap::getTerrainType(float x, float y) const -{ - if (!_liquidFlags) - return map_liquidHeaderTypeFlags::NoWater; - - x = 16 * (CENTER_GRID_ID - x/SIZE_OF_GRIDS); - y = 16 * (CENTER_GRID_ID - 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, Optional<map_liquidHeaderTypeFlags> ReqLiquidType, LiquidData* data, float collisionHeight) { @@ -2495,7 +2526,7 @@ float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float if (GridMap* gmap = GetGrid(terrainMapId, x, y)) { float gridHeight = gmap->getHeight(x, y); - if (z > gridHeight) + if (G3D::fuzzyGe(z, gridHeight - GROUND_HEIGHT_TOLERANCE)) mapHeight = gridHeight; } @@ -2537,46 +2568,12 @@ float Map::GetMinHeight(PhaseShift const& phaseShift, float x, float y) return -500.0f; } -inline bool IsOutdoorWMO(uint32 mogpFlags, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) +static inline bool IsInWMOInterior(uint32 mogpFlags) { - if (wmoEntry && atEntry) - { - if (atEntry->Flags[0] & AREA_FLAG_OUTSIDE) - return true; - if (atEntry->Flags[0] & AREA_FLAG_INSIDE) - return false; - } - - if (wmoEntry) - { - if (wmoEntry->Flags & 4) - return true; - if (wmoEntry->Flags & 2) - return false; - } - return (mogpFlags & 0x8); + return (mogpFlags & 0x2000) != 0; } -bool Map::IsOutdoors(PhaseShift const& phaseShift, float x, float y, float z) -{ - uint32 mogpFlags; - int32 adtId, rootId, groupId; - - // no wmo found? -> outside by default - if (!GetAreaInfo(phaseShift, x, y, z, mogpFlags, adtId, rootId, groupId)) - return true; - - AreaTableEntry const* atEntry = nullptr; - WMOAreaTableEntry const* wmoEntry = sDB2Manager.GetWMOAreaTable(rootId, adtId, groupId); - if (wmoEntry) - { - TC_LOG_DEBUG("maps", "Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->AreaTableID); - atEntry = sAreaTableStore.LookupEntry(wmoEntry->AreaTableID); - } - return IsOutdoorWMO(mogpFlags, wmoEntry, atEntry); -} - -bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) +bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) { float vmap_z = z; float dynamic_z = z; @@ -2594,8 +2591,8 @@ bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, u bool hasVmapAreaInfo = vmgr->getAreaInfo(terrainMapId, x, y, vmap_z, vflags, vadtId, vrootId, vgroupId); bool hasDynamicAreaInfo = _dynamicTree.getAreaInfo(x, y, dynamic_z, phaseShift, 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; }; + auto useVmap = [&]() { check_z = vmap_z; mogpflags = vflags; adtId = vadtId; rootId = vrootId; groupId = vgroupId; }; + auto useDyn = [&]() { check_z = dynamic_z; mogpflags = dflags; adtId = dadtId; rootId = drootId; groupId = dgroupId; }; if (hasVmapAreaInfo) { @@ -2615,7 +2612,8 @@ bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, u if (GridMap* gmap = GetGrid(terrainMapId, x, y)) { float mapHeight = gmap->getHeight(x, y); - if (z > mapHeight && mapHeight > vmap_z) + // 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; @@ -2623,43 +2621,39 @@ bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, u return false; } -uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors) +uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) { uint32 mogpFlags; int32 adtId, rootId, groupId; - WMOAreaTableEntry const* wmoEntry = nullptr; - AreaTableEntry const* atEntry = nullptr; - bool haveAreaInfo = false; - uint32 areaId = 0; + float vmapZ = z; + bool hasVmapArea = GetAreaInfo(phaseShift, x, y, vmapZ, mogpFlags, adtId, rootId, groupId); - if (GetAreaInfo(phaseShift, x, y, z, mogpFlags, adtId, rootId, groupId)) + uint32 gridAreaId = 0; + float gridMapHeight = INVALID_HEIGHT; + if (GridMap* gmap = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y)) { - haveAreaInfo = true; - wmoEntry = sDB2Manager.GetWMOAreaTable(rootId, adtId, groupId); - if (wmoEntry) - { - areaId = wmoEntry->AreaTableID; - atEntry = sAreaTableStore.LookupEntry(wmoEntry->AreaTableID); - } + gridAreaId = gmap->getArea(x, y); + gridMapHeight = gmap->getHeight(x, y); } - if (!areaId) + uint32 areaId = 0; + + // 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 = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y)) - areaId = gmap->getArea(x, y); + // wmo found + if (WMOAreaTableEntry const* wmoEntry = sDB2Manager.GetWMOAreaTable(rootId, adtId, groupId)) + areaId = wmoEntry->AreaTableID; - // this used while not all *.map files generated (instances) if (!areaId) - areaId = i_mapEntry->AreaTableID; + areaId = gridAreaId; } + else + areaId = gridAreaId; + + if (!areaId) + areaId = i_mapEntry->AreaTableID; - if (isOutdoors) - { - if (haveAreaInfo) - *isOutdoors = IsOutdoorWMO(mogpFlags, wmoEntry, atEntry); - else - *isOutdoors = true; - } return areaId; } @@ -2681,14 +2675,6 @@ void Map::GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& zoneid = area->ParentAreaID; } -map_liquidHeaderTypeFlags Map::GetTerrainType(PhaseShift const& phaseShift, float x, float y) -{ - if (GridMap* gmap = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y)) - return gmap->getTerrainType(x, y); - else - return map_liquidHeaderTypeFlags::NoWater; -} - ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, map_liquidHeaderTypeFlags ReqLiquidType, LiquidData* data, float collisionHeight) { ZLiquidStatus result = LIQUID_MAP_NO_WATER; @@ -2696,12 +2682,15 @@ ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float float liquid_level = INVALID_HEIGHT; float ground_level = INVALID_HEIGHT; uint32 liquid_type = 0; + uint32 mogpFlags = 0; + bool useGridLiquid = true; uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y); - if (vmgr->GetLiquidLevel(terrainMapId, x, y, z, AsUnderlyingType(ReqLiquidType), liquid_level, ground_level, liquid_type)) + if (vmgr->GetLiquidLevel(terrainMapId, x, y, z, AsUnderlyingType(ReqLiquidType), liquid_level, ground_level, liquid_type, mogpFlags)) { + useGridLiquid = !IsInWMOInterior(mogpFlags); TC_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) @@ -2754,22 +2743,25 @@ ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float } } - if (GridMap* gmap = GetGrid(terrainMapId, x, y)) + if (useGridLiquid) { - LiquidData map_data; - ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &map_data, collisionHeight); - // 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 = GetGrid(terrainMapId, x, y)) { - if (data) + LiquidData map_data; + ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &map_data, collisionHeight); + // Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER: + if (map_result != 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; + if (data) + { + // hardcoded in client like this + if (GetId() == 530 && map_data.entry == 2) + map_data.entry = 15; - *data = map_data; + *data = map_data; + } + return map_result; } - return map_result; } } return result; @@ -2779,58 +2771,87 @@ void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, { VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); VMAP::AreaAndLiquidData vmapData; + VMAP::AreaAndLiquidData dynData; + VMAP::AreaAndLiquidData* wmoData = nullptr; uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y); + GridMap* gmap = GetGrid(terrainMapId, x, y); vmgr->getAreaAndLiquidData(terrainMapId, x, y, z, AsUnderlyingType(reqLiquidType), vmapData); - if (vmapData.areaInfo) - data.areaInfo = boost::in_place(vmapData.areaInfo->adtId, vmapData.areaInfo->rootId, vmapData.areaInfo->groupId, vmapData.areaInfo->mogpFlags); + _dynamicTree.getAreaAndLiquidData(x, y, z, phaseShift, AsUnderlyingType(reqLiquidType), dynData); - float mapHeight = VMAP_INVALID_HEIGHT; - GridMap* gmap = GetGrid(terrainMapId, x, y); + uint32 gridAreaId = 0; + float gridMapHeight = INVALID_HEIGHT; if (gmap) - mapHeight = gmap->getHeight(x, y); - - // area lookup - AreaTableEntry const* areaEntry = nullptr; - WMOAreaTableEntry const* wmoEntry = nullptr; - // the vmap floor is our floor if either - // - the vmap floor is above the gridmap floor - // or - // - we are below the gridmap floor - if (vmapData.areaInfo && (G3D::fuzzyLt(z, mapHeight - GROUND_HEIGHT_TOLERANCE) || mapHeight <= vmapData.floorZ)) - if ((wmoEntry = sDB2Manager.GetWMOAreaTable(vmapData.areaInfo->rootId, vmapData.areaInfo->adtId, vmapData.areaInfo->groupId))) - areaEntry = sAreaTableStore.LookupEntry(wmoEntry->AreaTableID); - - if (areaEntry) - { - data.areaId = areaEntry->ID; + { + 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; } - else + // 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)) { - if (gmap) - data.areaId = gmap->getArea(x, y); - else - data.areaId = 0; + data.floorZ = dynData.floorZ; + wmoData = &dynData; + } - if (!data.areaId) - data.areaId = i_mapEntry->AreaTableID; + if (wmoData) + { + if (wmoData->areaInfo) + { + data.areaInfo.emplace(wmoData->areaInfo->adtId, wmoData->areaInfo->rootId, wmoData->areaInfo->groupId, wmoData->areaInfo->mogpFlags); + // wmo found + WMOAreaTableEntry const* wmoEntry = sDB2Manager.GetWMOAreaTable(wmoData->areaInfo->rootId, wmoData->areaInfo->adtId, wmoData->areaInfo->groupId); + data.outdoors = (wmoData->areaInfo->mogpFlags & 0x8) != 0; + if (wmoEntry) + { + data.areaId = wmoEntry->AreaTableID; + if (wmoEntry->Flags & 4) + data.outdoors = true; + else if (wmoEntry->Flags & 2) + data.outdoors = false; + } - if (data.areaId) - areaEntry = sAreaTableStore.LookupEntry(data.areaId); + if (!data.areaId) + data.areaId = gridAreaId; - data.floorZ = mapHeight; + useGridLiquid = !IsInWMOInterior(wmoData->areaInfo->mogpFlags); + } } - - if (vmapData.areaInfo) - data.outdoors = IsOutdoorWMO(vmapData.areaInfo->mogpFlags, wmoEntry, areaEntry); else - data.outdoors = true; // @todo default true taken from old GetAreaId check, maybe review + { + data.outdoors = true; + data.areaId = gridAreaId; + if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId)) + data.outdoors = (areaEntry->Flags[0] & (AREA_FLAG_INSIDE | AREA_FLAG_OUTSIDE)) != AREA_FLAG_INSIDE; + } + + if (!data.areaId) + data.areaId = i_mapEntry->AreaTableID; + + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId); // liquid processing data.liquidStatus = LIQUID_MAP_NO_WATER; - if (vmapData.liquidInfo && vmapData.liquidInfo->level > vmapData.floorZ && z > 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; @@ -2855,13 +2876,13 @@ void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, } } - data.liquidInfo = boost::in_place(); - data.liquidInfo->level = vmapData.liquidInfo->level; - data.liquidInfo->depth_level = vmapData.floorZ; + data.liquidInfo.emplace(); + data.liquidInfo->level = wmoData->liquidInfo->level; + data.liquidInfo->depth_level = wmoData->floorZ; data.liquidInfo->entry = liquidType; data.liquidInfo->type_flags = map_liquidHeaderTypeFlags(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) @@ -2872,11 +2893,11 @@ void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, data.liquidStatus = LIQUID_MAP_ABOVE_WATER; } // look up liquid data from grid map - if (gmap && (data.liquidStatus == LIQUID_MAP_ABOVE_WATER || data.liquidStatus == LIQUID_MAP_NO_WATER)) + if (gmap && useGridLiquid) { 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; diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 212a6d46d30..811aba5082b 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -155,9 +155,13 @@ class TC_GAME_API GridMap uint8 _liquidWidth; uint8 _liquidHeight; + uint8* _holes; + bool loadAreaData(FILE* in, uint32 offset, uint32 size); bool loadHeightData(FILE* in, uint32 offset, uint32 size); bool loadLiquidData(FILE* in, uint32 offset, uint32 size); + bool loadHolesData(FILE* in, uint32 offset, uint32 size); + bool isHole(int row, int col) const; // Get height functions and pointers typedef float (GridMap::*GetHeightPtr) (float x, float y) const; @@ -185,7 +189,6 @@ public: inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);} float getMinHeight(float x, float y) const; float getLiquidLevel(float x, float y) const; - map_liquidHeaderTypeFlags getTerrainType(float x, float y) const; ZLiquidStatus GetLiquidStatus(float x, float y, float z, Optional<map_liquidHeaderTypeFlags> ReqLiquidType, LiquidData* data = nullptr, float collisionHeight = 2.03128f); // DEFAULT_COLLISION_HEIGHT in Object.h }; @@ -334,16 +337,13 @@ class TC_GAME_API Map : public GridRefManager<NGridType> ZLiquidStatus GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, map_liquidHeaderTypeFlags ReqLiquidType, LiquidData* data = nullptr, float collisionHeight = 2.03128f); // DEFAULT_COLLISION_HEIGHT in Object.h bool GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId); - uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors = nullptr); + uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z); uint32 GetAreaId(PhaseShift const& phaseShift, Position const& pos) { return GetAreaId(phaseShift, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); } uint32 GetZoneId(PhaseShift const& phaseShift, float x, float y, float z); uint32 GetZoneId(PhaseShift const& phaseShift, Position const& pos) { return GetZoneId(phaseShift, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); } void GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, float x, float y, float z); void GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, Position const& pos) { GetZoneAndAreaId(phaseShift, zoneid, areaid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); } - bool IsOutdoors(PhaseShift const& phaseShift, float x, float y, float z); - - map_liquidHeaderTypeFlags GetTerrainType(PhaseShift const& phaseShift, float x, float y); float GetWaterLevel(PhaseShift const& phaseShift, float x, float y); bool IsInWater(PhaseShift const& phaseShift, float x, float y, float z, LiquidData* data = nullptr); bool IsUnderWater(PhaseShift const& phaseShift, float x, float y, float z); diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index cb3ecd2cc0e..d83b8edc763 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -581,7 +581,10 @@ void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoin void PathGenerator::NormalizePath() { for (uint32 i = 0; i < _pathPoints.size(); ++i) + { + _pathPoints[i].z += _sourceUnit->GetCollisionHeight(); _sourceUnit->UpdateAllowedPositionZ(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z); + } } void PathGenerator::BuildShortcut() diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 7016e7c4964..1e6db3d8923 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -1827,7 +1827,7 @@ private: { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id, difficulty); - if (requireOutdoors && !targetPlayer->GetMap()->IsOutdoors(targetPlayer->GetPhaseShift(), targetPlayer->GetPositionX(), targetPlayer->GetPositionY(), targetPlayer->GetPositionZ())) + if (requireOutdoors && !targetPlayer->IsOutdoors()) return SPELL_FAILED_ONLY_OUTDOORS; return spellInfo->CheckLocation(targetPlayer->GetMapId(), targetPlayer->GetZoneId(), targetPlayer->GetAreaId(), targetPlayer); diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 30981ec0f6e..10de95f15cb 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -568,7 +568,7 @@ namespace MMAP int cellRow = row / 8; // 8 squares per cell int cellCol = col / 8; int holeRow = row % 8; - int holeCol = (square - (row * 128 + cellCol * 8)); + int holeCol = col % 8; return (holes[cellRow][cellCol][holeRow] & (1 << holeCol)) != 0; } |