diff --git a/src/openrct2/ParkFile.cpp b/src/openrct2/ParkFile.cpp index 62d5b1c108..6f32203b60 100644 --- a/src/openrct2/ParkFile.cpp +++ b/src/openrct2/ParkFile.cpp @@ -794,8 +794,7 @@ namespace OpenRCT2 } else { - ReorganiseTileElements(); - const auto& tileElements = GetTileElements(); + auto tileElements = GetReorganisedTileElementsWithoutGhosts(); cs.Write(static_cast(tileElements.size())); cs.Write(tileElements.data(), tileElements.size() * sizeof(TileElement)); } diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 3de5f286be..92e259dd6d 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -605,67 +605,6 @@ bool scenario_prepare_for_save() return true; } -/** - * Modifies the given S6 data so that ghost elements, rides with no track elements or unused banners / user strings are saved. - */ -void scenario_fix_ghosts(rct_s6_data* s6) -{ - // Build tile pointer cache (needed to get the first element at a certain location) - RCT12TileElement* tilePointers[MAX_TILE_TILE_ELEMENT_POINTERS]; - for (size_t i = 0; i < MAX_TILE_TILE_ELEMENT_POINTERS; i++) - { - tilePointers[i] = TILE_UNDEFINED_TILE_ELEMENT; - } - - RCT12TileElement* tileElement = s6->tile_elements; - RCT12TileElement** tile = tilePointers; - for (size_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) - { - for (size_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) - { - *tile++ = tileElement; - while (!(tileElement++)->IsLastForTile()) - ; - } - } - - // Remove all ghost elements - RCT12TileElement* destinationElement = s6->tile_elements; - - for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) - { - for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) - { - // This is the equivalent of map_get_first_element_at(x, y), but on S6 data. - RCT12TileElement* originalElement = tilePointers[x + y * MAXIMUM_MAP_SIZE_TECHNICAL]; - do - { - if (originalElement->IsGhost()) - { - uint8_t bannerIndex = originalElement->GetBannerIndex(); - if (bannerIndex != RCT12_BANNER_INDEX_NULL) - { - auto banner = &s6->banners[bannerIndex]; - if (banner->type != RCT12_OBJECT_ENTRY_INDEX_NULL) - { - banner->type = RCT12_OBJECT_ENTRY_INDEX_NULL; - if (is_user_string_id(banner->string_idx)) - s6->custom_strings[(banner->string_idx % RCT12_MAX_USER_STRINGS)][0] = 0; - } - } - } - else - { - *destinationElement++ = *originalElement; - } - } while (!(originalElement++)->IsLastForTile()); - - // Set last element flag in case the original last element was never added - (destinationElement - 1)->flags |= TILE_ELEMENT_FLAG_LAST_TILE; - } - } -} - ObjectiveStatus Objective::CheckGuestsBy() const { int16_t parkRating = gParkRating; diff --git a/src/openrct2/scenario/Scenario.h b/src/openrct2/scenario/Scenario.h index 5b57829505..1197917925 100644 --- a/src/openrct2/scenario/Scenario.h +++ b/src/openrct2/scenario/Scenario.h @@ -459,8 +459,6 @@ uint32_t scenario_rand_max(uint32_t max); bool scenario_prepare_for_save(); int32_t scenario_save(const utf8* path, int32_t flags); -void scenario_remove_trackless_rides(rct_s6_data* s6); -void scenario_fix_ghosts(rct_s6_data* s6); void scenario_failure(); void scenario_success(); void scenario_success_submit_name(const char* name); diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 2be43a52f9..00f9b547ba 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -146,6 +146,61 @@ void SetTileElements(std::vector&& tileElements) _tileIndex = TilePointerIndex(MAXIMUM_MAP_SIZE_TECHNICAL, _tileElements.data()); } +static TileElement GetDefaultSurfaceElement() +{ + TileElement el; + el.ClearAs(TILE_ELEMENT_TYPE_SURFACE); + el.SetLastForTile(true); + el.base_height = 14; + el.clearance_height = 14; + el.AsSurface()->SetWaterHeight(0); + el.AsSurface()->SetSlope(TILE_ELEMENT_SLOPE_FLAT); + el.AsSurface()->SetGrassLength(GRASS_LENGTH_CLEAR_0); + el.AsSurface()->SetOwnership(OWNERSHIP_UNOWNED); + el.AsSurface()->SetParkFences(0); + el.AsSurface()->SetSurfaceStyle(0); + el.AsSurface()->SetEdgeStyle(0); + return el; +} + +std::vector GetReorganisedTileElementsWithoutGhosts() +{ + std::vector newElements; + newElements.reserve(std::max(MIN_TILE_ELEMENTS, _tileElements.size())); + for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) + { + for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) + { + auto oldSize = newElements.size(); + + // Add all non-ghost elements + const auto* element = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); + if (element != nullptr) + { + do + { + if (!element->IsGhost()) + { + newElements.push_back(*element); + } + } while (!(element++)->IsLastForTile()); + } + + // Insert default surface element if no elements were added + auto newSize = newElements.size(); + if (oldSize == newSize) + { + newElements.push_back(GetDefaultSurfaceElement()); + } + + // Ensure last element of tile has last flag set + auto& lastEl = newElements.back(); + lastEl.SetLastForTile(true); + } + } + return newElements; +} + static void ReorganiseTileElements(size_t capacity) { context_setcurrentcursor(CursorID::ZZZ); @@ -159,18 +214,7 @@ static void ReorganiseTileElements(size_t capacity) const auto* element = map_get_first_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); if (element == nullptr) { - auto& newElement = newElements.emplace_back(); - newElement.ClearAs(TILE_ELEMENT_TYPE_SURFACE); - newElement.SetLastForTile(true); - newElement.base_height = 14; - newElement.clearance_height = 14; - newElement.AsSurface()->SetWaterHeight(0); - newElement.AsSurface()->SetSlope(TILE_ELEMENT_SLOPE_FLAT); - newElement.AsSurface()->SetGrassLength(GRASS_LENGTH_CLEAR_0); - newElement.AsSurface()->SetOwnership(OWNERSHIP_UNOWNED); - newElement.AsSurface()->SetParkFences(0); - newElement.AsSurface()->SetSurfaceStyle(0); - newElement.AsSurface()->SetEdgeStyle(0); + newElements.push_back(GetDefaultSurfaceElement()); } else { diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 2786994818..412756356c 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -189,6 +189,7 @@ const std::vector& GetTileElements(); void SetTileElements(std::vector&& tileElements); void StashMap(); void UnstashMap(); +std::vector GetReorganisedTileElementsWithoutGhosts(); void map_init(int32_t size);