22
33#include < cstddef>
44#include < cstdint>
5+ #include < cstring>
56#include < memory>
67#include < stack>
78#include < string>
@@ -78,12 +79,18 @@ std::unique_ptr<uint16_t[]> LoadMinData(size_t &tileCount)
7879{
7980 switch (leveltype) {
8081 case DTYPE_TOWN: {
81- auto min = LoadFileInMemWithStatus<uint16_t >(" nlevels\\ towndata\\ town.min" , &tileCount);
82+ const TownVisualAssets &active = GetActiveTownConfigForTileLoad ().visualAssets ;
83+ const TownVisualAssets &tristramAssets = GetTownRegistry ().GetTown (TristramTownId).visualAssets ;
84+ LogVerbose (" LoadMinData (town): {}" , active.pieceMinPath );
85+ auto min = LoadFileInMemWithStatus<uint16_t >(active.pieceMinPath .c_str (), &tileCount);
8286 if (!min.has_value ()) {
83- return LoadFileInMem<uint16_t >(" levels\\ towndata\\ town.min" , &tileCount);
84- } else {
87+ if (active.pieceMinPath != tristramAssets.pieceMinPath )
88+ min = LoadFileInMemWithStatus<uint16_t >(tristramAssets.pieceMinPath .c_str (), &tileCount);
89+ if (!min.has_value ())
90+ return LoadFileInMem<uint16_t >(TristramRetailTownPaths::PieceMin, &tileCount);
8591 return std::move (*min);
8692 }
93+ return std::move (*min);
8794 }
8895 case DTYPE_CATHEDRAL:
8996 return LoadFileInMem<uint16_t >(" levels\\ l1data\\ l1.min" , &tileCount);
@@ -443,11 +450,20 @@ void CreateDungeon(uint32_t rseed, lvl_entry entry)
443450tl::expected<void , std::string> LoadLevelSOLData ()
444451{
445452 switch (leveltype) {
446- case DTYPE_TOWN:
447- if (!LoadFileInMemWithStatus (" nlevels\\ towndata\\ town.sol" , SOLData).has_value ()) {
448- RETURN_IF_ERROR (LoadFileInMemWithStatus (" levels\\ towndata\\ town.sol" , SOLData));
453+ case DTYPE_TOWN: {
454+ const TownVisualAssets &active = GetActiveTownConfigForTileLoad ().visualAssets ;
455+ const TownVisualAssets &tristramAssets = GetTownRegistry ().GetTown (TristramTownId).visualAssets ;
456+ LogVerbose (" LoadLevelSOLData (town): {}" , active.solPath );
457+ if (!LoadFileInMemWithStatus (active.solPath .c_str (), SOLData).has_value ()) {
458+ // Try Tristram primary (skip if same path to avoid a redundant attempt).
459+ bool loaded = active.solPath != tristramAssets.solPath
460+ && LoadFileInMemWithStatus (tristramAssets.solPath .c_str (), SOLData).has_value ();
461+ if (!loaded) {
462+ RETURN_IF_ERROR (LoadFileInMemWithStatus (TristramRetailTownPaths::Sol, SOLData));
463+ }
449464 }
450465 break ;
466+ }
451467 case DTYPE_CATHEDRAL:
452468 RETURN_IF_ERROR (LoadFileInMemWithStatus (" levels\\ l1data\\ l1.sol" , SOLData));
453469 // Fix incorrectly marked arched tiles
@@ -509,12 +525,15 @@ tl::expected<void, std::string> LoadLevelSOLData()
509525
510526void SetDungeonMicros (std::unique_ptr<std::byte[]> &dungeonCels, uint_fast8_t µTileLen)
511527{
528+ // Clear the DPieceMicros array so if other towns have less tiles, they don't break with segfault
529+ std::memset (DPieceMicros, 0 , sizeof (DPieceMicros));
530+
512531 microTileLen = 10 ;
513532 size_t blocks = 10 ;
514533
515534 if (leveltype == DTYPE_TOWN) {
516- microTileLen = 16 ;
517- blocks = 16 ;
535+ microTileLen = GetActiveTownConfigForTileLoad (). visualAssets . microTileLen ;
536+ blocks = microTileLen ;
518537 } else if (leveltype == DTYPE_HELL) {
519538 microTileLen = 12 ;
520539 blocks = 16 ;
@@ -523,9 +542,14 @@ void SetDungeonMicros(std::unique_ptr<std::byte[]> &dungeonCels, uint_fast8_t &m
523542 size_t tileCount;
524543 const std::unique_ptr<uint16_t []> levelPieces = LoadMinData (tileCount);
525544
545+ const size_t pieceCount = tileCount / blocks;
546+ if (pieceCount > MAXTILES) {
547+ LogWarn (" Tileset has {} level pieces but the engine supports at most {}; extra pieces will be ignored." ,
548+ pieceCount, MAXTILES);
549+ }
526550 ankerl::unordered_dense::map<uint16_t , DunFrameInfo> frameToTypeMap;
527551 frameToTypeMap.reserve (4096 );
528- for (size_t levelPieceId = 0 ; levelPieceId < tileCount / blocks ; levelPieceId++) {
552+ for (size_t levelPieceId = 0 ; levelPieceId < std::min (pieceCount, static_cast < size_t >(MAXTILES)) ; levelPieceId++) {
529553 uint16_t *pieces = &levelPieces[blocks * levelPieceId];
530554 for (uint32_t block = 0 ; block < blocks; block++) {
531555 const LevelCelBlock levelCelBlock { Swap16LE (pieces[blocks - 2 + (block & 1 ) - (block & 0xE )]) };
@@ -546,7 +570,7 @@ void SetDungeonMicros(std::unique_ptr<std::byte[]> &dungeonCels, uint_fast8_t &m
546570
547571 std::vector<std::pair<uint16_t , uint16_t >> celBlockAdjustments = ComputeCelBlockAdjustments (frameToTypeList);
548572 if (celBlockAdjustments.size () == 0 ) return ;
549- for (size_t levelPieceId = 0 ; levelPieceId < tileCount / blocks ; levelPieceId++) {
573+ for (size_t levelPieceId = 0 ; levelPieceId < std::min (pieceCount, static_cast < size_t >(MAXTILES)) ; levelPieceId++) {
550574 for (uint32_t block = 0 ; block < blocks; block++) {
551575 LevelCelBlock &levelCelBlock = DPieceMicros[levelPieceId].mt [block];
552576 const uint16_t frame = levelCelBlock.frame ();
0 commit comments