diff --git a/Source/levels/gendung.cpp b/Source/levels/gendung.cpp index f53bed99a..ff4a5c9c2 100644 --- a/Source/levels/gendung.cpp +++ b/Source/levels/gendung.cpp @@ -524,11 +524,12 @@ void SetDungeonMicros() uint16_t *pieces = &levelPieces[blocks * levelPieceId]; for (uint32_t block = 0; block < blocks; block++) { const LevelCelBlock levelCelBlock { SDL_SwapLE16(pieces[blocks - 2 + (block & 1) - (block & 0xE)]) }; - DPieceMicros[levelPieceId].mt[block] = levelCelBlock; + LevelCelBlock &mt = DPieceMicros[levelPieceId].mt[block]; + mt = levelCelBlock; if (levelCelBlock.hasValue()) { if (const auto it = frameToTypeMap.find(levelCelBlock.frame()); it == frameToTypeMap.end()) { frameToTypeMap.emplace_hint(it, levelCelBlock.frame(), - DunFrameInfo { static_cast(block), levelCelBlock.type(), SOLData[levelPieceId] }); + DunFrameInfo { static_cast(block), levelCelBlock.type(), SOLData[levelPieceId], &mt.data }); } } } @@ -538,6 +539,7 @@ void SetDungeonMicros() return a.first < b.first; }); ReencodeDungeonCels(pDungeonCels, frameToTypeList); + ReindexCelBlocks(frameToTypeList); } void DRLG_InitTrans() diff --git a/Source/levels/reencode_dun_cels.cpp b/Source/levels/reencode_dun_cels.cpp index 01b289e3f..0121a16cd 100644 --- a/Source/levels/reencode_dun_cels.cpp +++ b/Source/levels/reencode_dun_cels.cpp @@ -252,9 +252,11 @@ void ReencodeDungeonCels(std::unique_ptr &dungeonCels, std::span result { new std::byte[outSize] }; auto *const resultPtr = reinterpret_cast(result.get()); WriteLE32(resultPtr, static_cast(frames.size())); + uint8_t *lookup = resultPtr + 4; uint8_t *out = resultPtr + (2 + frames.size()) * 4; // number of frames, frame offsets, file size for (const auto &[frame, info] : frames) { - WriteLE32(&resultPtr[static_cast(frame * 4)], static_cast(out - resultPtr)); + WriteLE32(lookup, static_cast(out - resultPtr)); + lookup += 4; const uint32_t srcFrameBegin = SDL_SwapLE32(srcOffsets[frame]); const uint8_t *src = &srcData[srcFrameBegin]; switch (info.type) { @@ -288,7 +290,7 @@ void ReencodeDungeonCels(std::unique_ptr &dungeonCels, std::span(outSize)); + WriteLE32(lookup, static_cast(outSize)); const auto *dstOffsets = reinterpret_cast(resultPtr); LogVerbose(" Re-encoded dungeon CELs: {} frames, {} bytes. Extracted {} foliage tiles.", @@ -299,4 +301,15 @@ void ReencodeDungeonCels(std::unique_ptr &dungeonCels, std::span> frames) +{ + uint16_t lastFrameIndex = 0; + uint16_t adjustment = 0; + for (auto &[frame, info] : frames) { + adjustment += frame - lastFrameIndex - 1; + lastFrameIndex = frame; + *info.celBlockData -= adjustment; + } +} + } // namespace devilution diff --git a/Source/levels/reencode_dun_cels.hpp b/Source/levels/reencode_dun_cels.hpp index c91482d86..145101c1c 100644 --- a/Source/levels/reencode_dun_cels.hpp +++ b/Source/levels/reencode_dun_cels.hpp @@ -17,6 +17,8 @@ struct DunFrameInfo { TileType type; TileProperties properties; + uint16_t *celBlockData; + [[nodiscard]] bool isFloor() const { // The BlockMissile check is for stairs in L3 and L4, e.g. tile 46 sub-tile 141 frame 386 in L4. @@ -36,4 +38,12 @@ struct DunFrameInfo { */ void ReencodeDungeonCels(std::unique_ptr &dungeonCels, std::span> frames); +/** + * @brief Adjusts frame indexes in cel block data. + * + * Re-encoding the dungeon cels removes frames that are not referenced. + * Indexes must also be adjusted to avoid errors when doing lookups. + */ +void ReindexCelBlocks(std::span> frames); + } // namespace devilution