diff --git a/Source/levels/gendung.cpp b/Source/levels/gendung.cpp index ff4a5c9c2..dbe575f66 100644 --- a/Source/levels/gendung.cpp +++ b/Source/levels/gendung.cpp @@ -524,12 +524,11 @@ 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)]) }; - LevelCelBlock &mt = DPieceMicros[levelPieceId].mt[block]; - mt = levelCelBlock; + DPieceMicros[levelPieceId].mt[block] = 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], &mt.data }); + DunFrameInfo { static_cast(block), levelCelBlock.type(), SOLData[levelPieceId] }); } } } @@ -539,7 +538,21 @@ void SetDungeonMicros() return a.first < b.first; }); ReencodeDungeonCels(pDungeonCels, frameToTypeList); - ReindexCelBlocks(frameToTypeList); + + std::vector> celBlockAdjustments = ComputeCelBlockAdjustments(frameToTypeList); + if (celBlockAdjustments.size() == 0) return; + for (size_t levelPieceId = 0; levelPieceId < tileCount / blocks; levelPieceId++) { + for (uint32_t block = 0; block < blocks; block++) { + LevelCelBlock &levelCelBlock = DPieceMicros[levelPieceId].mt[block]; + const uint16_t frame = levelCelBlock.frame(); + const auto pair = std::make_pair(frame, frame); + const auto it = std::upper_bound(celBlockAdjustments.begin(), celBlockAdjustments.end(), pair, + [](std::pair p1, std::pair p2) { return p1.first < p2.first; }); + if (it != celBlockAdjustments.end()) { + levelCelBlock.data -= it->second; + } + } + } } void DRLG_InitTrans() diff --git a/Source/levels/reencode_dun_cels.cpp b/Source/levels/reencode_dun_cels.cpp index 0121a16cd..ec23854a3 100644 --- a/Source/levels/reencode_dun_cels.cpp +++ b/Source/levels/reencode_dun_cels.cpp @@ -3,9 +3,11 @@ #include #include #include +#include #include #include #include +#include #include @@ -301,15 +303,21 @@ void ReencodeDungeonCels(std::unique_ptr &dungeonCels, std::span> frames) +std::vector> ComputeCelBlockAdjustments(std::span> frames) { + std::vector> celBlockAdjustments; uint16_t lastFrameIndex = 0; uint16_t adjustment = 0; for (auto &[frame, info] : frames) { - adjustment += frame - lastFrameIndex - 1; + uint16_t diff = frame - lastFrameIndex - 1; + if (diff > 0) celBlockAdjustments.emplace_back(frame, adjustment); + adjustment += diff; lastFrameIndex = frame; - *info.celBlockData -= adjustment; } + if (adjustment > 0) { + celBlockAdjustments.emplace_back(std::numeric_limits::max(), adjustment); + } + return celBlockAdjustments; } } // namespace devilution diff --git a/Source/levels/reencode_dun_cels.hpp b/Source/levels/reencode_dun_cels.hpp index 145101c1c..dafa21429 100644 --- a/Source/levels/reencode_dun_cels.hpp +++ b/Source/levels/reencode_dun_cels.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "levels/dun_tile.hpp" @@ -17,8 +18,6 @@ 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. @@ -39,11 +38,11 @@ struct DunFrameInfo { void ReencodeDungeonCels(std::unique_ptr &dungeonCels, std::span> frames); /** - * @brief Adjusts frame indexes in cel block data. + * @brief Computes adjustments to apply to 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); +std::vector> ComputeCelBlockAdjustments(std::span> frames); } // namespace devilution