aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2016-02-09 00:14:58 +0100
committerShauren <shauren.trinity@gmail.com>2016-02-09 00:14:58 +0100
commit4f78efd4633f79285f176b61367a067b2cd90e2b (patch)
tree252dff34f55f084d097aecea3d269882d6286b0d /src
parentb9f1dffa14fbd340634b035e05e59063d0028bfa (diff)
Core/Maps: Parse MFBO adt chunk to properly handle height where player counts as falling under the map
* This fixes the height at which player is instantly killed when falling from The Frozen Throne * Set PLAYER_FLAGS_IS_OUT_OF_BOUNDS on players under the map to enable release spirit button while still falling Note: Extracting new maps is required
Diffstat (limited to 'src')
-rw-r--r--src/server/game/DataStores/DBCStructure.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp7
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp3
-rw-r--r--src/server/game/Maps/Map.cpp62
-rw-r--r--src/server/game/Maps/Map.h11
-rw-r--r--src/tools/map_extractor/CMakeLists.txt2
-rw-r--r--src/tools/map_extractor/System.cpp107
-rw-r--r--src/tools/map_extractor/adt.h16
-rw-r--r--src/tools/map_extractor/loadlib.cpp3
-rw-r--r--src/tools/mmaps_generator/TerrainBuilder.cpp2
10 files changed, 186 insertions, 30 deletions
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index f051184b7e7..ec334fb3b8f 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -34,9 +34,6 @@ struct AnimKitEntry
//uint32 LowDefAnimKitID; // 3
};
-// Temporary define until max depth is found somewhere (adt?)
-#define MAX_MAP_DEPTH -5000
-
struct AreaTableEntry
{
uint32 ID; // 0
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index b3007affd83..7e30a125827 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -4235,6 +4235,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
// remove death flag + set aura
SetByteValue(UNIT_FIELD_BYTES_1, 3, 0x00);
+ RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
// This must be called always even on Players with race != RACE_NIGHTELF in case of faction change
RemoveAurasDueToSpell(20584); // RACE_NIGHTELF speed bonuses
@@ -4635,7 +4636,7 @@ void Player::RepopAtGraveyard()
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId());
// Such zones are considered unreachable as a ghost and the player must be automatically revived
- if ((!IsAlive() && zone && zone->Flags[0] & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < MAX_MAP_DEPTH)
+ if ((!IsAlive() && zone && zone->Flags[0] & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
{
ResurrectPlayer(0.5f);
SpawnCorpseBones();
@@ -4670,8 +4671,10 @@ void Player::RepopAtGraveyard()
GetSession()->SendPacket(packet.Write());
}
}
- else if (GetPositionZ() < MAX_MAP_DEPTH)
+ else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
+
+ RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
}
bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone) const
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index fb391229340..3ab9f683dea 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -382,7 +382,7 @@ void WorldSession::HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMov
plrMover->UpdateFallInformationIfNeed(movementInfo, opcode);
- if (movementInfo.pos.GetPositionZ() < MAX_MAP_DEPTH)
+ if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY()))
{
if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player)))
{
@@ -391,6 +391,7 @@ void WorldSession::HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMov
/// @todo discard movement packets after the player is rooted
if (plrMover->IsAlive())
{
+ plrMover->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());
// player can be alive if GM/etc
// change the death state to CORPSE to prevent the death timer from
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 510d678821b..304f1ef7c2a 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -40,7 +40,7 @@
#include "Weather.h"
u_map_magic MapMagic = { {'M','A','P','S'} };
-u_map_magic MapVersionMagic = { {'v','1','.','6'} };
+u_map_magic MapVersionMagic = { {'v','1','.','7'} };
u_map_magic MapAreaMagic = { {'A','R','E','A'} };
u_map_magic MapHeightMagic = { {'M','H','G','T'} };
u_map_magic MapLiquidMagic = { {'M','L','I','Q'} };
@@ -1655,13 +1655,15 @@ GridMap::GridMap()
_flags = 0;
// Area data
_gridArea = 0;
- _areaMap = NULL;
+ _areaMap = nullptr;
// Height level data
_gridHeight = INVALID_HEIGHT;
_gridGetHeight = &GridMap::getHeightFromFlat;
_gridIntHeightMultiplier = 0;
- m_V9 = NULL;
- m_V8 = NULL;
+ m_V9 = nullptr;
+ m_V8 = nullptr;
+ _maxHeight = nullptr;
+ _minHeight = nullptr;
// Liquid data
_liquidType = 0;
_liquidOffX = 0;
@@ -1669,9 +1671,9 @@ GridMap::GridMap()
_liquidWidth = 0;
_liquidHeight = 0;
_liquidLevel = INVALID_HEIGHT;
- _liquidEntry = NULL;
- _liquidFlags = NULL;
- _liquidMap = NULL;
+ _liquidEntry = nullptr;
+ _liquidFlags = nullptr;
+ _liquidMap = nullptr;
}
GridMap::~GridMap()
@@ -1734,15 +1736,19 @@ void GridMap::unloadData()
delete[] _areaMap;
delete[] m_V9;
delete[] m_V8;
+ delete[] _maxHeight;
+ delete[] _minHeight;
delete[] _liquidEntry;
delete[] _liquidFlags;
delete[] _liquidMap;
- _areaMap = NULL;
- m_V9 = NULL;
- m_V8 = NULL;
- _liquidEntry = NULL;
- _liquidFlags = NULL;
- _liquidMap = NULL;
+ _areaMap = nullptr;
+ m_V9 = nullptr;
+ m_V8 = nullptr;
+ _maxHeight = nullptr;
+ _minHeight = nullptr;
+ _liquidEntry = nullptr;
+ _liquidFlags = nullptr;
+ _liquidMap = nullptr;
_gridGetHeight = &GridMap::getHeightFromFlat;
}
@@ -1807,6 +1813,16 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/)
}
else
_gridGetHeight = &GridMap::getHeightFromFlat;
+
+ if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS)
+ {
+ _maxHeight = new float[16 * 16];
+ _minHeight = new float[16 * 16];
+ if (fread(_maxHeight, sizeof(float), 16 * 16, in) != 16 * 16 ||
+ fread(_minHeight, sizeof(float), 16 * 16, in) != 16 * 16)
+ return false;
+ }
+
return true;
}
@@ -2077,6 +2093,18 @@ float GridMap::getHeightFromUint16(float x, float y) const
return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight;
}
+float GridMap::getMinHeight(float x, float y) const
+{
+ if (!_minHeight)
+ return -500.0f;
+
+ 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 _minHeight[lx * 16 + ly];
+}
+
float GridMap::getLiquidLevel(float x, float y) const
{
if (!_liquidMap)
@@ -2277,6 +2305,14 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
return mapHeight; // explicitly use map data
}
+float Map::GetMinHeight(float x, float y) const
+{
+ if (GridMap const* grid = const_cast<Map*>(this)->GetGrid(x, y))
+ return grid->getMinHeight(x, y);
+
+ return -500.0f;
+}
+
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)
{
bool outdoor = true;
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index bf8770cfd30..bf29a257419 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -100,9 +100,10 @@ struct map_areaHeader
uint16 gridArea;
};
-#define MAP_HEIGHT_NO_HEIGHT 0x0001
-#define MAP_HEIGHT_AS_INT16 0x0002
-#define MAP_HEIGHT_AS_INT8 0x0004
+#define MAP_HEIGHT_NO_HEIGHT 0x0001
+#define MAP_HEIGHT_AS_INT16 0x0002
+#define MAP_HEIGHT_AS_INT8 0x0004
+#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008
struct map_heightHeader
{
@@ -168,6 +169,8 @@ class GridMap
uint16* m_uint16_V8;
uint8* m_uint8_V8;
};
+ float* _maxHeight;
+ float* _minHeight;
// Height level data
float _gridHeight;
float _gridIntHeightMultiplier;
@@ -208,6 +211,7 @@ public:
uint16 getArea(float x, float y) const;
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;
uint8 getTerrainType(float x, float y) const;
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
@@ -329,6 +333,7 @@ class Map : public GridRefManager<NGridType>
// some calls like isInWater should not use vmaps due to processor power
// can return INVALID_HEIGHT if under z+2 z coord not found height
float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
+ float GetMinHeight(float x, float y) const;
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const;
diff --git a/src/tools/map_extractor/CMakeLists.txt b/src/tools/map_extractor/CMakeLists.txt
index 32fccaa2038..58435a51121 100644
--- a/src/tools/map_extractor/CMakeLists.txt
+++ b/src/tools/map_extractor/CMakeLists.txt
@@ -14,6 +14,7 @@ file(GLOB_RECURSE sources *.cpp *.h)
include_directories (
${CMAKE_SOURCE_DIR}/dep/CascLib/src
${CMAKE_SOURCE_DIR}/dep/cppformat
+ ${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/src/common
${CMAKE_SOURCE_DIR}/src/common/Utilities
${CMAKE_SOURCE_DIR}/src/server/shared
@@ -31,6 +32,7 @@ target_link_libraries(mapextractor
casc
common
format
+ g3dlib
${BZIP2_LIBRARIES}
${ZLIB_LIBRARIES}
${Boost_LIBRARIES}
diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp
index 2d36df68df1..a079ab42367 100644
--- a/src/tools/map_extractor/System.cpp
+++ b/src/tools/map_extractor/System.cpp
@@ -40,6 +40,8 @@
#include "adt.h"
#include "wdt.h"
+#include <G3D/Plane.h>
+
namespace
{
const char* HumanReadableCASCError(int error)
@@ -351,7 +353,7 @@ void ReadLiquidTypeTableDBC()
// Map file format data
static char const* MAP_MAGIC = "MAPS";
-static char const* MAP_VERSION_MAGIC = "v1.6";
+static char const* MAP_VERSION_MAGIC = "v1.7";
static char const* MAP_AREA_MAGIC = "AREA";
static char const* MAP_HEIGHT_MAGIC = "MHGT";
static char const* MAP_LIQUID_MAGIC = "MLIQ";
@@ -380,9 +382,10 @@ struct map_areaHeader
uint16 gridArea;
};
-#define MAP_HEIGHT_NO_HEIGHT 0x0001
-#define MAP_HEIGHT_AS_INT16 0x0002
-#define MAP_HEIGHT_AS_INT8 0x0004
+#define MAP_HEIGHT_NO_HEIGHT 0x0001
+#define MAP_HEIGHT_AS_INT16 0x0002
+#define MAP_HEIGHT_AS_INT8 0x0004
+#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008
struct map_heightHeader
{
@@ -442,14 +445,17 @@ bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE];
float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
uint8 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID][8];
-bool TransformToHighRes(uint16 holes, uint8 hiResHoles[8])
+float flight_box_max[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
+float flight_box_min[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
+
+bool TransformToHighRes(uint16 lowResHoles, uint8 hiResHoles[8])
{
for (uint8 i = 0; i < 8; i++)
{
for (uint8 j = 0; j < 8; j++)
{
int32 holeIdxL = (i / 2) * 4 + (j / 2);
- if (((holes >> holeIdxL) & 1) == 1)
+ if (((lowResHoles >> holeIdxL) & 1) == 1)
hiResHoles[i] |= (1 << j);
}
}
@@ -482,6 +488,7 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int
memset(holes, 0, sizeof(holes));
bool hasHoles = false;
+ bool hasFlightBox = false;
for (std::multimap<std::string, FileChunk*>::const_iterator itr = adt.chunks.lower_bound("MCNK"); itr != adt.chunks.upper_bound("MCNK"); ++itr)
{
@@ -696,6 +703,82 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int
}
}
+ if (FileChunk* chunk = adt.GetChunk("MFBO"))
+ {
+ static uint32 const indices[] =
+ {
+ 3, 0, 4,
+ 0, 1, 4,
+ 1, 2, 4,
+ 2, 5, 4,
+ 5, 8, 4,
+ 8, 7, 4,
+ 7, 6, 4,
+ 6, 3, 4
+ };
+
+ static float const boundGridCoords[] =
+ {
+ 0.0f, 0.0f,
+ 0.0f, -266.66666f,
+ 0.0f, -533.33331f,
+ -266.66666f, 0.0f,
+ -266.66666f, -266.66666f,
+ -266.66666f, -533.33331f,
+ -533.33331f, 0.0f,
+ -533.33331f, -266.66666f,
+ -533.33331f, -533.33331f
+ };
+
+ adt_MFBO* mfbo = chunk->As<adt_MFBO>();
+ for (int gy = 0; gy < ADT_CELLS_PER_GRID; ++gy)
+ {
+ for (int gx = 0; gx < ADT_CELLS_PER_GRID; ++gx)
+ {
+ int32 quarterIndex = 0;
+ if (gy > ADT_CELLS_PER_GRID / 2)
+ {
+ if (gx > ADT_CELLS_PER_GRID / 2)
+ {
+ quarterIndex = 4 + gx < gy;
+ }
+ else
+ quarterIndex = 2;
+ }
+ else if (gx > ADT_CELLS_PER_GRID / 2)
+ {
+ quarterIndex = 7;
+ }
+ else
+ quarterIndex = gx > gy;
+
+ quarterIndex *= 3;
+ G3D::Plane planeMax(
+ G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 0]]),
+ G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 1]]),
+ G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 2]])
+ );
+
+ G3D::Plane planeMin(
+ G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 0]]),
+ G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 1]]),
+ G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 2]])
+ );
+
+ auto non_nan_distance = [](G3D::Plane const& plane){
+ auto d = plane.distance(G3D::Vector3(0.0f, 0.0f, 0.0f));
+ assert(!G3D::isNaN(d));
+ return d;
+ };
+
+ flight_box_max[gy][gx] = non_nan_distance(planeMax);
+ flight_box_min[gy][gx] = non_nan_distance(planeMin);
+ }
+ }
+
+ hasFlightBox = true;
+ }
+
//============================================
// Try pack area data
//============================================
@@ -787,6 +870,12 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int
if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit)
heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT;
+ if (hasFlightBox)
+ {
+ heightHeader.flags |= MAP_HEIGHT_HAS_FLIGHT_BOUNDS;
+ map.heightMapSize += sizeof(flight_box_max) + sizeof(flight_box_min);
+ }
+
// Try store as packed in uint16 or uint8 values
if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT))
{
@@ -958,6 +1047,12 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int
}
}
+ if (heightHeader.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS)
+ {
+ outFile.write(reinterpret_cast<char*>(flight_box_max), sizeof(flight_box_max));
+ outFile.write(reinterpret_cast<char*>(flight_box_min), sizeof(flight_box_min));
+ }
+
// Store liquid data if need
if (map.liquidMapOffset)
{
diff --git a/src/tools/map_extractor/adt.h b/src/tools/map_extractor/adt.h
index 0c3b3780c16..bb6980507b7 100644
--- a/src/tools/map_extractor/adt.h
+++ b/src/tools/map_extractor/adt.h
@@ -219,6 +219,22 @@ struct adt_MH2O
};
+struct adt_MFBO
+{
+ union
+ {
+ uint32 fcc;
+ char fcc_txt[4];
+ };
+ uint32 size;
+ struct plane
+ {
+ int16 coords[9];
+ };
+ plane max;
+ plane min;
+};
+
#pragma pack(pop)
#endif
diff --git a/src/tools/map_extractor/loadlib.cpp b/src/tools/map_extractor/loadlib.cpp
index 39bbe5b1412..067683577f4 100644
--- a/src/tools/map_extractor/loadlib.cpp
+++ b/src/tools/map_extractor/loadlib.cpp
@@ -96,7 +96,8 @@ u_map_fcc InterestingChunks[] =
{ { 'K', 'N', 'C', 'M' } },
{ { 'T', 'V', 'C', 'M' } },
{ { 'O', 'M', 'W', 'M' } },
- { { 'Q', 'L', 'C', 'M' } }
+ { { 'Q', 'L', 'C', 'M' } },
+ { { 'O', 'B', 'F', 'M' } }
};
bool IsInterestingChunk(u_map_fcc const& fcc)
diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp
index 33832f8986d..c4a32882c1d 100644
--- a/src/tools/mmaps_generator/TerrainBuilder.cpp
+++ b/src/tools/mmaps_generator/TerrainBuilder.cpp
@@ -80,7 +80,7 @@ struct map_liquidHeader
namespace MMAP
{
- char const* MAP_VERSION_MAGIC = "v1.6";
+ char const* MAP_VERSION_MAGIC = "v1.7";
TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ }
TerrainBuilder::~TerrainBuilder() { }