diff options
author | Shauren <shauren.trinity@gmail.com> | 2018-04-07 00:21:51 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2018-04-07 21:36:15 +0200 |
commit | b9c6bbb51df0ed10f74617482740fedb91ff5366 (patch) | |
tree | 9b54a41e2a8fe0075983548d2a31977e6cdd2a58 /src/server/game/Maps/Map.cpp | |
parent | 2dadbda24ac1c2e6ff3dad650c7e25f4b3322342 (diff) |
Core/Maps: Adjusted logic in GetFullTerrainStatusForPosition to closer match what the client does regarding being inside WMOs
Closes #21625
Closes #21624
Closes #21516
Diffstat (limited to 'src/server/game/Maps/Map.cpp')
-rw-r--r-- | src/server/game/Maps/Map.cpp | 263 |
1 files changed, 128 insertions, 135 deletions
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index afe5e8d6727..e99d33e62c2 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -51,6 +51,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 }; + #define DEFAULT_GRID_EXPIRY 300 #define MAX_GRID_LOAD_TIME 50 #define MAX_CREATURE_ATTACK_RADIUS (45.0f * sWorld->getRate(RATE_CREATURE_AGGRO)) @@ -1746,6 +1749,7 @@ GridMap::GridMap() _liquidEntry = nullptr; _liquidFlags = nullptr; _liquidMap = nullptr; + _holes = nullptr; } GridMap::~GridMap() @@ -1793,6 +1797,13 @@ bool GridMap::loadData(char const* filename) fclose(in); return false; } + // 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 false; + } fclose(in); return true; } @@ -1813,6 +1824,7 @@ void GridMap::unloadData() delete[] _liquidEntry; delete[] _liquidFlags; delete[] _liquidMap; + delete[] _holes; _areaMap = nullptr; m_V9 = nullptr; m_V8 = nullptr; @@ -1821,6 +1833,7 @@ void GridMap::unloadData() _liquidEntry = nullptr; _liquidFlags = nullptr; _liquidMap = nullptr; + _holes = nullptr; _gridGetHeight = &GridMap::getHeightFromFlat; } @@ -1932,6 +1945,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) @@ -1964,6 +1989,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: @@ -2046,6 +2074,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) @@ -2113,6 +2144,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) @@ -2165,6 +2199,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) @@ -2244,19 +2293,6 @@ 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 * (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, uint8 ReqLiquidType, LiquidData* data, float collisionHeight) { @@ -2398,7 +2434,7 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y)) { float gridHeight = gmap->getHeight(x, y); - if (z > gridHeight) + if (G3D::fuzzyGe(z, gridHeight - GROUND_HEIGHT_TOLERANCE)) mapHeight = gridHeight; } @@ -2440,101 +2476,44 @@ float Map::GetMinHeight(float x, float y) const return -500.0f; } -inline bool IsOutdoorWMO(uint32 mogpFlags, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) -{ - if (wmoEntry && atEntry) - { - if (atEntry->flags & AREA_FLAG_OUTSIDE) - return true; - if (atEntry->flags & AREA_FLAG_INSIDE) - return false; - } - - if (wmoEntry) - { - if (wmoEntry->Flags & 4) - return true; - if (wmoEntry->Flags & 2) - return false; - } - - return (mogpFlags & 0x8); -} - -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 = nullptr; - WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId); - if (wmoEntry) - { - TC_LOG_DEBUG("maps", "Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId); - atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId); - } - return IsOutdoorWMO(mogpFlags, wmoEntry, atEntry); -} - -bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const +static inline bool IsInWMOInterior(uint32 mogpFlags) { - float vmap_z = z; - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - if (vmgr->getAreaInfo(GetId(), x, y, vmap_z, flags, adtId, rootId, groupId)) - { - // 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); - if (z > _mapheight && _mapheight > vmap_z) - return false; - } - return true; + return (mogpFlags & 0x2000) != 0; } - return false; -} -uint32 Map::GetAreaId(float x, float y, float z, bool *isOutdoors) const +uint32 Map::GetAreaId(float x, float y, float z) const { uint32 mogpFlags; int32 adtId, rootId, groupId; - WMOAreaTableEntry const* wmoEntry = nullptr; - AreaTableEntry const* atEntry = nullptr; - bool haveAreaInfo = false; + float vmapZ; + bool hasVmapArea = VMAP::VMapFactory::createOrGetVMapManager()->getAreaInfo(GetId(), 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); } uint32 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); + // wmo found + if (WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId)) + areaId = wmoEntry->areaId; - // this used while not all *.map files generated (instances) if (!areaId) - areaId = i_mapEntry->linked_zone; + areaId = gridAreaId; } + else + areaId = gridAreaId; + + if (!areaId) + areaId = i_mapEntry->linked_zone; - if (isOutdoors) - { - if (haveAreaInfo) - *isOutdoors = IsOutdoorWMO(mogpFlags, wmoEntry, atEntry); - else - *isOutdoors = true; - } return areaId; } @@ -2556,14 +2535,6 @@ void Map::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, flo zoneid = area->zone; } -uint8 Map::GetTerrainType(float x, float y) const -{ - if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y)) - return gmap->getTerrainType(x, y); - else - return 0; -} - ZLiquidStatus Map::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data, float collisionHeight) const { ZLiquidStatus result = LIQUID_MAP_NO_WATER; @@ -2571,11 +2542,14 @@ ZLiquidStatus Map::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp 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)) { + 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) @@ -2628,6 +2602,8 @@ ZLiquidStatus Map::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp } } + if (useGridLiquid) + { if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y)) { LiquidData map_data; @@ -2646,6 +2622,7 @@ ZLiquidStatus Map::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp return map_result; } } + } return result; } @@ -2653,55 +2630,71 @@ void Map::GetFullTerrainStatusForPosition(float x, float y, float z, PositionFul { VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); VMAP::AreaAndLiquidData vmapData; + GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y); vmgr->getAreaAndLiquidData(GetId(), x, y, z, reqLiquidType, vmapData); - if (vmapData.areaInfo) - data.areaInfo = boost::in_place(vmapData.areaInfo->adtId, vmapData.areaInfo->rootId, vmapData.areaInfo->groupId, vmapData.areaInfo->mogpFlags); - float mapHeight = VMAP_INVALID_HEIGHT; - GridMap* gmap = const_cast<Map*>(this)->GetGrid(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 = GetWMOAreaTableEntryByTripple(vmapData.areaInfo->rootId, vmapData.areaInfo->adtId, vmapData.areaInfo->groupId))) - areaEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId); + { + gridAreaId = gmap->getArea(x, y); + gridMapHeight = gmap->getHeight(x, y); + } - data.areaId = 0; + bool vmapLocation = false; + bool useGridLiquid = true; - if (areaEntry) + // 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.areaId = areaEntry->ID; data.floorZ = vmapData.floorZ; + vmapLocation = true; + } + + if (vmapLocation) + { + if (vmapData.areaInfo) + { + data.areaInfo = boost::in_place(vmapData.areaInfo->adtId, vmapData.areaInfo->rootId, vmapData.areaInfo->groupId, vmapData.areaInfo->mogpFlags); + // wmo found + WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(vmapData.areaInfo->rootId, vmapData.areaInfo->adtId, vmapData.areaInfo->groupId); + data.outdoors = (vmapData.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(vmapData.areaInfo->mogpFlags); + } } else { - if (gmap) - data.areaId = gmap->getArea(x, y); + 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; - if (data.areaId) - areaEntry = sAreaTableStore.LookupEntry(data.areaId); - - data.floorZ = mapHeight; - } - - 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 + 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 (vmapLocation && vmapData.liquidInfo && vmapData.liquidInfo->level > vmapData.floorZ) { uint32 liquidType = vmapData.liquidInfo->type; if (GetId() == 530 && liquidType == 2) // gotta love blizzard hacks @@ -2745,7 +2738,7 @@ void Map::GetFullTerrainStatusForPosition(float x, float y, float z, PositionFul 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); |