From d78c2af9f5dfa898f29306a488f25d227f892540 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Thu, 29 Oct 2026 21:47:52 +0100 Subject: [PATCH] bugfix(worldheightmap): Restore Generals retail compatibility of the cliff state of maps up to version 7 Merging the Height Map code gave Generals the cliff state rows of Zero Hour, which have (width+7)/8 bytes. Retail Generals keeps them in rows of (width+1)/8 bytes, which are too short for the last cells of a row when the map width modulo 8 is 2 to 6. These cells share their bit with the first cells of the next row. Since the merge they read as no cliff instead, so the pathfinder classifies them differently and retail Generals replays on such maps mismatch. A retail compatible Generals now restores the shared values after loading. For version 7 maps the last cells of a row take the stored bits of the first cells of the next row. For older maps, whose flags are computed from the heights column by column, the first cells of the next row take the flags of the last cells, which retail computes last. Without retail compatibility, Generals and Zero Hour compute the flags of these cells from the heights for version 7 maps, because the file has no bits for them. Steep slopes in the last columns of such maps are no longer passable for ground units. A retail compatible Zero Hour and all version 8 maps keep the cliff state as before. --- .../W3DDevice/GameClient/WorldHeightMap.cpp | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp index f28441cf359..73dbe9bc359 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp @@ -1139,7 +1139,8 @@ Bool WorldHeightMap::ParseBlendTileData(DataChunkInput &file, DataChunkInfo *inf } if (info->version >= K_BLEND_TILE_VERSION_7) { if (info->version==K_BLEND_TILE_VERSION_7) { - Int byteWidth = (m_width+1)/8; // previous incorrect length that got used to save the file. jba. [4/3/2003] + // previous incorrect length that got used to save the file. jba. [4/3/2003] + Int byteWidth = (m_width+1)/8; UnsignedByte *data = new UnsignedByte[m_height*byteWidth]; file.readArrayOfBytes((char*)data, m_height*byteWidth); for (j=0; jversion <= K_BLEND_TILE_VERSION_7) { + const Int retailRowCells = 8*((m_width+1)/8); + for (j=0; jversion == K_BLEND_TILE_VERSION_7) { + // The file holds the shared bits in the first cells of the next row. + setCliffState(i, j, getCliffState(i-retailRowCells, j+1)); + } else { + // The flags are computed column by column, so the last cells of a row are written last. + setCliffState(i-retailRowCells, j+1, getCliffState(i, j)); + } + } + } + } +#elif !RETAIL_COMPATIBLE_CRC + // Version 7 files have no bits for the last cells of a row, so they are computed from the heights. + if (info->version == K_BLEND_TILE_VERSION_7) { + const Int retailRowCells = 8*((m_width+1)/8); + for (j=0; j0 && m_numBitmapTiles<2048, ("Unlikely numBitmapTiles.")); m_numBlendedTiles = file.readInt();