diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index 50ebe225d4..0ceca0ea71 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -2392,7 +2392,7 @@ static void window_ride_construction_draw_track_piece( } static TileElement _tempTrackTileElement; -static TileElement _tempSideTrackTileElement = { 0x80, 0x8F, 128, 128, 0, 0, 0, 0 }; +static TileElement _tempSideTrackTileElement = { 0x80, 0x8F, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static TileElement* _backupTileElementArrays[5]; /** diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index 2d95f8e016..f86e7b0a6a 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -664,7 +664,7 @@ static void window_tile_inspector_copy_element(rct_window* w) static void window_tile_inspector_paste_element(rct_window* w) { // Construct the data to send using the surface's properties - int32_t data[2]; + int32_t data[4]; std::memcpy(&data[0], &tileInspectorCopiedElement, 8); assert_struct_size(data, sizeof(tileInspectorCopiedElement)); auto modifyTile = TileModifyAction(windowTileInspectorToolMap, TileModifyType::AnyPaste, 0, 0, tileInspectorCopiedElement); diff --git a/src/openrct2/rct12/RCT12.cpp b/src/openrct2/rct12/RCT12.cpp index ecc7ec3317..9d5abb929e 100644 --- a/src/openrct2/rct12/RCT12.cpp +++ b/src/openrct2/rct12/RCT12.cpp @@ -16,6 +16,8 @@ #include "../world/Surface.h" #include "../world/TileElement.h" #include "../world/Wall.h" +#include "../world/Banner.h" +#include "../world/LargeScenery.h" uint8_t RCT12TileElementBase::GetType() const { @@ -452,3 +454,28 @@ std::string RCT12::RemoveFormatCodes(const std::string_view& s) return result; } + +uint8_t RCT12TileElement::GetBannerIndex() +{ + rct_scenery_entry* sceneryEntry; + + switch (GetType()) + { + case TILE_ELEMENT_TYPE_LARGE_SCENERY: + sceneryEntry = get_large_scenery_entry(AsLargeScenery()->GetEntryIndex()); + if (sceneryEntry->large_scenery.scrolling_mode == SCROLLING_MODE_NONE) + return BANNER_INDEX_NULL; + + return AsLargeScenery()->GetBannerIndex(); + case TILE_ELEMENT_TYPE_WALL: + sceneryEntry = get_wall_entry(AsWall()->GetEntryIndex()); + if (sceneryEntry == nullptr || sceneryEntry->wall.scrolling_mode == SCROLLING_MODE_NONE) + return BANNER_INDEX_NULL; + + return AsWall()->GetBannerIndex(); + case TILE_ELEMENT_TYPE_BANNER: + return AsBanner()->GetIndex(); + default: + return BANNER_INDEX_NULL; + } +} diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index d61a36ac14..3141a4e6c7 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -212,6 +212,7 @@ struct RCT12TileElement : public RCT12TileElementBase return as(); } void ClearAs(uint8_t newType); + uint8_t GetBannerIndex(); }; assert_struct_size(RCT12TileElement, 8); struct RCT12SurfaceElement : RCT12TileElementBase diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 81e0f00995..a88431cb19 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -605,11 +605,28 @@ bool scenario_prepare_for_save() /** * Modifies the given S6 data so that ghost elements, rides with no track elements or unused banners / user strings are saved. - * - * TODO: This employs some black casting magic that should go away once we export to our own format instead of SV6. */ 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; @@ -617,12 +634,13 @@ void scenario_fix_ghosts(rct_s6_data* s6) { for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) { - RCT12TileElement* originalElement = reinterpret_cast(map_get_first_element_at(x, y)); + // 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()) { - BannerIndex bannerIndex = tile_element_get_banner_index(reinterpret_cast(originalElement)); + BannerIndex bannerIndex = originalElement->GetBannerIndex(); if (bannerIndex != BANNER_INDEX_NULL) { auto banner = &s6->banners[bannerIndex]; diff --git a/src/openrct2/world/TileElement.h b/src/openrct2/world/TileElement.h index b2841720c8..f1a81ce5f0 100644 --- a/src/openrct2/world/TileElement.h +++ b/src/openrct2/world/TileElement.h @@ -64,6 +64,8 @@ struct TileElementBase uint8_t flags; // 1 uint8_t base_height; // 2 uint8_t clearance_height; // 3 + + uint8_t testPad[8]; uint8_t GetType() const; void SetType(uint8_t newType); @@ -129,7 +131,7 @@ public: void ClearAs(uint8_t newType); }; -assert_struct_size(TileElement, 8); +assert_struct_size(TileElement, 16); struct SurfaceElement : TileElementBase { @@ -165,7 +167,7 @@ public: bool HasTrackThatNeedsWater() const; void SetHasTrackThatNeedsWater(bool on); }; -assert_struct_size(SurfaceElement, 8); +assert_struct_size(SurfaceElement, 16); struct PathElement : TileElementBase { @@ -241,7 +243,7 @@ public: bool ShouldDrawPathOverSupports(); void SetShouldDrawPathOverSupports(bool on); }; -assert_struct_size(PathElement, 8); +assert_struct_size(PathElement, 16); struct TrackElement : TileElementBase { @@ -326,7 +328,7 @@ public: uint8_t GetDoorAState() const; uint8_t GetDoorBState() const; }; -assert_struct_size(TrackElement, 8); +assert_struct_size(TrackElement, 16); struct SmallSceneryElement : TileElementBase { @@ -351,7 +353,7 @@ public: bool NeedsSupports() const; void SetNeedsSupports(); }; -assert_struct_size(SmallSceneryElement, 8); +assert_struct_size(SmallSceneryElement, 16); struct LargeSceneryElement : TileElementBase { @@ -378,7 +380,7 @@ public: bool IsAccounted() const; void SetIsAccounted(bool isAccounted); }; -assert_struct_size(LargeSceneryElement, 8); +assert_struct_size(LargeSceneryElement, 16); struct WallElement : TileElementBase { @@ -423,7 +425,7 @@ public: int32_t GetRCT1WallType(int32_t edge) const; colour_t GetRCT1WallColour() const; }; -assert_struct_size(WallElement, 8); +assert_struct_size(WallElement, 16); struct EntranceElement : TileElementBase { @@ -449,7 +451,7 @@ public: uint8_t GetPathType() const; void SetPathType(uint8_t newPathType); }; -assert_struct_size(EntranceElement, 8); +assert_struct_size(EntranceElement, 16); struct BannerElement : TileElementBase { @@ -475,13 +477,13 @@ public: void SetAllowedEdges(uint8_t newEdges); void ResetAllowedEdges(); }; -assert_struct_size(BannerElement, 8); +assert_struct_size(BannerElement, 16); struct CorruptElement : TileElementBase { uint8_t pad[4]; }; -assert_struct_size(CorruptElement, 8); +assert_struct_size(CorruptElement, 16); #pragma pack(pop) class QuarterTile