diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index 3de0bbb2f0..8347652e9d 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -2453,7 +2453,8 @@ static void sub_6CBCE2( _tempTrackTileElement.SetType(TILE_ELEMENT_TYPE_TRACK); _tempTrackTileElement.SetDirection(trackDirection); _tempTrackTileElement.AsTrack()->SetHasChain((edx & 0x10000) != 0); - _tempTrackTileElement.flags = quarterTile.GetBaseQuarterOccupied() | TILE_ELEMENT_FLAG_LAST_TILE; + _tempTrackTileElement.SetOccupiedQuadrants(quarterTile.GetBaseQuarterOccupied()); + _tempTrackTileElement.SetLastForTile(true); _tempTrackTileElement.base_height = baseZ; _tempTrackTileElement.clearance_height = clearanceZ; _tempTrackTileElement.AsTrack()->SetTrackType(trackType); diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index f6911ed71f..9af60dfe70 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -1613,10 +1613,11 @@ static void window_tile_inspector_invalidate(rct_window* w) w->widgets[WIDX_SCENERY_CHECK_COLLISION_S].bottom = w->widgets[WIDX_SCENERY_CHECK_COLLISION_S].top + 13; w->widgets[WIDX_SCENERY_CHECK_COLLISION_W].top = GBBT(propertiesAnchor, 2) + 5 + 7 * 1; w->widgets[WIDX_SCENERY_CHECK_COLLISION_W].bottom = w->widgets[WIDX_SCENERY_CHECK_COLLISION_W].top + 13; - N = (tileElement->flags & (1 << ((2 - get_current_rotation()) & 3))) != 0; - E = (tileElement->flags & (1 << ((3 - get_current_rotation()) & 3))) != 0; - S = (tileElement->flags & (1 << ((0 - get_current_rotation()) & 3))) != 0; - W = (tileElement->flags & (1 << ((1 - get_current_rotation()) & 3))) != 0; + auto occupiedQuadrants = tileElement->GetOccupiedQuadrants(); + N = (occupiedQuadrants & (1 << ((2 - get_current_rotation()) & 3))) != 0; + E = (occupiedQuadrants & (1 << ((3 - get_current_rotation()) & 3))) != 0; + S = (occupiedQuadrants & (1 << ((0 - get_current_rotation()) & 3))) != 0; + W = (occupiedQuadrants & (1 << ((1 - get_current_rotation()) & 3))) != 0; widget_set_checkbox_value(w, WIDX_SCENERY_CHECK_COLLISION_N, N); widget_set_checkbox_value(w, WIDX_SCENERY_CHECK_COLLISION_E, E); widget_set_checkbox_value(w, WIDX_SCENERY_CHECK_COLLISION_S, S); diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index f43d162129..2032e8e63c 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -643,7 +643,7 @@ void game_fix_save_vars() if (surfaceElement == nullptr) { log_error("Null map element at x = %d and y = %d. Fixing...", x, y); - auto tileElement = tile_element_insert({ x, y, 14 }, 0); + auto tileElement = tile_element_insert({ x, y, 14 }, 0b0000); if (tileElement == nullptr) { log_error("Unable to fix: Map element limit reached."); diff --git a/src/openrct2/actions/BannerPlaceAction.hpp b/src/openrct2/actions/BannerPlaceAction.hpp index 08dd5aefe3..6821f54902 100644 --- a/src/openrct2/actions/BannerPlaceAction.hpp +++ b/src/openrct2/actions/BannerPlaceAction.hpp @@ -137,7 +137,7 @@ public: return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_CANT_POSITION_THIS_HERE); } - TileElement* newTileElement = tile_element_insert({ _loc.x / 32, _loc.y / 32, baseHeight }, 0); + TileElement* newTileElement = tile_element_insert({ _loc.x / 32, _loc.y / 32, baseHeight }, 0b0000); assert(newTileElement != nullptr); banner->flags = 0; diff --git a/src/openrct2/actions/MazeSetTrackAction.hpp b/src/openrct2/actions/MazeSetTrackAction.hpp index 8fb7444601..cd156af7cc 100644 --- a/src/openrct2/actions/MazeSetTrackAction.hpp +++ b/src/openrct2/actions/MazeSetTrackAction.hpp @@ -216,7 +216,7 @@ public: uint16_t flooredX = floor2(_loc.x, 32); uint16_t flooredY = floor2(_loc.y, 32); - tileElement = tile_element_insert({ _loc.x / 32, _loc.y / 32, baseHeight }, 0xF); + tileElement = tile_element_insert({ _loc.x / 32, _loc.y / 32, baseHeight }, 0b1111); assert(tileElement != nullptr); tileElement->clearance_height = clearanceHeight; diff --git a/src/openrct2/actions/PlaceParkEntranceAction.hpp b/src/openrct2/actions/PlaceParkEntranceAction.hpp index 1048caf9de..9d45e2edda 100644 --- a/src/openrct2/actions/PlaceParkEntranceAction.hpp +++ b/src/openrct2/actions/PlaceParkEntranceAction.hpp @@ -146,7 +146,7 @@ public: surfaceElement->SetOwnership(OWNERSHIP_UNOWNED); } - TileElement* newElement = tile_element_insert({ entranceLoc.x / 32, entranceLoc.y / 32, zLow }, 0xF); + TileElement* newElement = tile_element_insert({ entranceLoc.x / 32, entranceLoc.y / 32, zLow }, 0b1111); Guard::Assert(newElement != nullptr); newElement->SetType(TILE_ELEMENT_TYPE_ENTRANCE); auto entranceElement = newElement->AsEntrance(); diff --git a/src/openrct2/actions/WallPlaceAction.hpp b/src/openrct2/actions/WallPlaceAction.hpp index 718a301dfd..cf581f64f1 100644 --- a/src/openrct2/actions/WallPlaceAction.hpp +++ b/src/openrct2/actions/WallPlaceAction.hpp @@ -394,7 +394,7 @@ public: return std::make_unique(GA_ERROR::NO_FREE_ELEMENTS, gGameCommandErrorText); } - TileElement* tileElement = tile_element_insert({ _loc.x / 32, _loc.y / 32, targetHeight / 8 }, 0); + TileElement* tileElement = tile_element_insert({ _loc.x / 32, _loc.y / 32, targetHeight / 8 }, 0b0000); assert(tileElement != nullptr); map_animation_create(MAP_ANIMATION_TYPE_WALL, _loc.x, _loc.y, targetHeight / 8); @@ -643,7 +643,7 @@ private: } continue; } - if ((tileElement->flags & 0x0F) == 0) + if (tileElement->GetOccupiedQuadrants() == 0) continue; switch (elementType) diff --git a/src/openrct2/core/DataSerialiserTraits.h b/src/openrct2/core/DataSerialiserTraits.h index f44389e675..c6b91dc10e 100644 --- a/src/openrct2/core/DataSerialiserTraits.h +++ b/src/openrct2/core/DataSerialiserTraits.h @@ -393,6 +393,10 @@ template<> struct DataSerializerTraits { stream->WriteValue(tileElement.pad_04[i]); } + for (int i = 0; i < 8; ++i) + { + stream->WriteValue(tileElement.pad_08[i]); + } } static void decode(IStream* stream, TileElement& tileElement) { @@ -404,6 +408,10 @@ template<> struct DataSerializerTraits { tileElement.pad_04[i] = stream->ReadValue(); } + for (int i = 0; i < 8; ++i) + { + tileElement.pad_08[i] = stream->ReadValue(); + } } static void log(IStream* stream, const TileElement& tileElement) { diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 8cd788f202..73e6450338 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -2015,7 +2015,7 @@ private: void ImportTileElement(TileElement* dst, const RCT12TileElement* src) { - // Todo: allow for changing defition of OpenRCT2 tile element types - replace with a map + // Todo: allow for changing definition of OpenRCT2 tile element types - replace with a map uint8_t tileElementType = src->GetType(); dst->ClearAs(tileElementType); dst->SetDirection(src->GetDirection()); @@ -2694,7 +2694,7 @@ private: for (int32_t y = 0; y < RCT1_MAX_MAP_SIZE; y++) { nextFreeTileElement->ClearAs(TILE_ELEMENT_TYPE_SURFACE); - nextFreeTileElement->flags = TILE_ELEMENT_FLAG_LAST_TILE; + nextFreeTileElement->SetLastForTile(true); nextFreeTileElement->AsSurface()->SetSlope(TILE_ELEMENT_SLOPE_FLAT); nextFreeTileElement->AsSurface()->SetSurfaceStyle(TERRAIN_GRASS); nextFreeTileElement->AsSurface()->SetEdgeStyle(TERRAIN_EDGE_ROCK); @@ -2708,7 +2708,7 @@ private: for (int32_t y = 0; y < 128 * 256; y++) { nextFreeTileElement->ClearAs(TILE_ELEMENT_TYPE_SURFACE); - nextFreeTileElement->flags = TILE_ELEMENT_FLAG_LAST_TILE; + nextFreeTileElement->SetLastForTile(true); nextFreeTileElement->AsSurface()->SetSlope(TILE_ELEMENT_SLOPE_FLAT); nextFreeTileElement->AsSurface()->SetSurfaceStyle(TERRAIN_GRASS); nextFreeTileElement->AsSurface()->SetEdgeStyle(TERRAIN_EDGE_ROCK); diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index 4f2a8f7d6a..9b1dc60a1f 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -166,7 +166,7 @@ struct RCT12EightCarsCorruptElement15; struct RCT12TileElementBase { uint8_t type; // 0 - uint8_t flags; // 1 + uint8_t flags; // 1. Upper nibble: flags. Lower nibble: occupied quadrants (one bit per quadrant). uint8_t base_height; // 2 uint8_t clearance_height; // 3 uint8_t GetType() const; diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 32e616a506..642df48b92 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -2184,7 +2184,7 @@ static money32 place_maze_design(uint8_t flags, Ride* ride, uint16_t mazeEntry, int32_t fx = floor2(x, 32); int32_t fy = floor2(y, 32); int32_t fz = z >> 3; - TileElement* tileElement = tile_element_insert({ fx >> 5, fy >> 5, fz }, 15); + TileElement* tileElement = tile_element_insert({ fx >> 5, fy >> 5, fz }, 0b1111); tileElement->clearance_height = fz + 4; tileElement->SetType(TILE_ELEMENT_TYPE_TRACK); tileElement->AsTrack()->SetTrackType(TRACK_ELEM_MAZE); @@ -2411,7 +2411,7 @@ static void track_design_preview_clear_map() { TileElement* tile_element = &gTileElements[i]; tile_element->ClearAs(TILE_ELEMENT_TYPE_SURFACE); - tile_element->flags = TILE_ELEMENT_FLAG_LAST_TILE; + tile_element->SetLastForTile(true); tile_element->AsSurface()->SetSlope(TILE_ELEMENT_SLOPE_FLAT); tile_element->AsSurface()->SetWaterHeight(0); tile_element->AsSurface()->SetSurfaceStyle(TERRAIN_GRASS); diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index a36e058338..b91afac957 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -5169,18 +5169,18 @@ static TileElement* vehicle_check_collision(int16_t x, int16_t y, int16_t z) return nullptr; } - uint8_t bl; + uint8_t quadrant; if ((x & 0x1F) >= 16) { - bl = 1; + quadrant = 1; if ((y & 0x1F) < 16) - bl = 2; + quadrant = 2; } else { - bl = 4; + quadrant = 4; if ((y & 0x1F) >= 16) - bl = 8; + quadrant = 8; } do @@ -5191,7 +5191,7 @@ static TileElement* vehicle_check_collision(int16_t x, int16_t y, int16_t z) if (z / 8 >= tileElement->clearance_height) continue; - if (tileElement->flags & bl) + if (tileElement->GetOccupiedQuadrants() & quadrant) return tileElement; } while (!(tileElement++)->IsLastForTile()); @@ -6769,7 +6769,8 @@ static void vehicle_update_block_brakes_open_previous_section(rct_vehicle* vehic slowY = slowTrackBeginEnd.end_y; slowTileElement = *(slowTrackBeginEnd.begin_element); if (slowX == x && slowY == y && slowTileElement.base_height == tileElement->base_height - && slowTileElement.type == tileElement->type) + && slowTileElement.GetType() == tileElement->GetType() + && slowTileElement.GetDirection() == tileElement->GetDirection()) { return; } diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index db2b487bef..7eb2266367 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -310,7 +310,7 @@ void map_init(int32_t size) { TileElement* tile_element = &gTileElements[i]; tile_element->ClearAs(TILE_ELEMENT_TYPE_SURFACE); - tile_element->flags = TILE_ELEMENT_FLAG_LAST_TILE; + tile_element->SetLastForTile(true); tile_element->base_height = 14; tile_element->clearance_height = 14; tile_element->AsSurface()->SetWaterHeight(0); @@ -957,7 +957,7 @@ void tile_element_remove(TileElement* tileElement) } // Mark the latest element with the last element flag. - (tileElement - 1)->flags |= TILE_ELEMENT_FLAG_LAST_TILE; + (tileElement - 1)->SetLastForTile(true); tileElement->base_height = 0xFF; if ((tileElement + 1) == gNextFreeTileElement) @@ -1153,9 +1153,10 @@ bool map_check_free_elements_and_reorganise(int32_t numElements) * * rct2: 0x0068B1F6 */ -TileElement* tile_element_insert(const TileCoordsXYZ& loc, int32_t flags) +TileElement* tile_element_insert(const TileCoordsXYZ& loc, int32_t occupiedQuadrants) { TileElement *originalTileElement, *newTileElement, *insertedElement; + bool isLastForTile = false; if (!map_check_free_elements_and_reorganise(1)) { @@ -1178,11 +1179,11 @@ TileElement* tile_element_insert(const TileCoordsXYZ& loc, int32_t flags) originalTileElement++; newTileElement++; - if ((newTileElement - 1)->flags & TILE_ELEMENT_FLAG_LAST_TILE) + if ((newTileElement - 1)->IsLastForTile()) { // No more elements above the insert element - (newTileElement - 1)->flags &= ~TILE_ELEMENT_FLAG_LAST_TILE; - flags |= TILE_ELEMENT_FLAG_LAST_TILE; + (newTileElement - 1)->SetLastForTile(false); + isLastForTile = true; break; } } @@ -1191,13 +1192,15 @@ TileElement* tile_element_insert(const TileCoordsXYZ& loc, int32_t flags) insertedElement = newTileElement; newTileElement->type = 0; newTileElement->base_height = loc.z; - newTileElement->flags = flags; + newTileElement->flags = 0; + newTileElement->SetLastForTile(isLastForTile); + newTileElement->SetOccupiedQuadrants(occupiedQuadrants); newTileElement->clearance_height = loc.z; std::memset(&newTileElement->pad_04, 0, sizeof(newTileElement->pad_04)); newTileElement++; // Insert rest of map elements above insert height - if (!(flags & TILE_ELEMENT_FLAG_LAST_TILE)) + if (!isLastForTile) { do { @@ -1285,8 +1288,8 @@ void map_obstruction_set_error_text(TileElement* tileElement) * bl = bl */ bool map_can_construct_with_clear_at( - int32_t x, int32_t y, int32_t zLow, int32_t zHigh, CLEAR_FUNC clearFunc, QuarterTile bl, uint8_t flags, money32* price, - uint8_t crossingMode) + int32_t x, int32_t y, int32_t zLow, int32_t zHigh, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags, + money32* price, uint8_t crossingMode) { int32_t al, ah, bh, cl, ch, water_height; al = ah = bh = cl = ch = water_height = 0; @@ -1312,7 +1315,7 @@ bool map_can_construct_with_clear_at( { if (zLow < tileElement->clearance_height && zHigh > tileElement->base_height && !(tileElement->IsGhost())) { - if (tileElement->flags & (bl.GetBaseQuarterOccupied())) + if (tileElement->GetOccupiedQuadrants() & (quarterTile.GetBaseQuarterOccupied())) { goto loc_68BABC; } @@ -1349,7 +1352,7 @@ bool map_can_construct_with_clear_at( canBuildCrossing = true; } - if (bl.GetZQuarterOccupied() != 0b1111) + if (quarterTile.GetZQuarterOccupied() != 0b1111) { if (tileElement->base_height >= zHigh) { @@ -1390,8 +1393,8 @@ bool map_can_construct_with_clear_at( } bh = zLow + 4; { - auto baseQuarter = bl.GetBaseQuarterOccupied(); - auto zQuarter = bl.GetZQuarterOccupied(); + auto baseQuarter = quarterTile.GetBaseQuarterOccupied(); + auto zQuarter = quarterTile.GetZQuarterOccupied(); if ((!(baseQuarter & 0b0001) || ((zQuarter & 0b0001 || zLow >= al) && bh >= al)) && (!(baseQuarter & 0b0010) || ((zQuarter & 0b0010 || zLow >= ah) && bh >= ah)) && (!(baseQuarter & 0b0100) || ((zQuarter & 0b0100 || zLow >= cl) && bh >= cl)) diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 5bf3e43e4a..f4fdf3bf82 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -172,15 +172,15 @@ void map_invalidate_map_selection_tiles(); void map_invalidate_selection_rect(); void map_reorganise_elements(); bool map_check_free_elements_and_reorganise(int32_t num_elements); -TileElement* tile_element_insert(const TileCoordsXYZ& loc, int32_t flags); +TileElement* tile_element_insert(const TileCoordsXYZ& loc, int32_t occupiedQuadrants); using CLEAR_FUNC = int32_t (*)(TileElement** tile_element, int32_t x, int32_t y, uint8_t flags, money32* price); int32_t map_place_non_scenery_clear_func(TileElement** tile_element, int32_t x, int32_t y, uint8_t flags, money32* price); int32_t map_place_scenery_clear_func(TileElement** tile_element, int32_t x, int32_t y, uint8_t flags, money32* price); bool map_can_construct_with_clear_at( - int32_t x, int32_t y, int32_t zLow, int32_t zHigh, CLEAR_FUNC clearFunc, QuarterTile bl, uint8_t flags, money32* price, - uint8_t crossingMode); + int32_t x, int32_t y, int32_t zLow, int32_t zHigh, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags, + money32* price, uint8_t crossingMode); int32_t map_can_construct_at(int32_t x, int32_t y, int32_t zLow, int32_t zHigh, QuarterTile bl); void rotate_map_coordinates(int16_t* x, int16_t* y, int32_t rotation); diff --git a/src/openrct2/world/MapAnimation.cpp b/src/openrct2/world/MapAnimation.cpp index aea7adfb70..85adc90060 100644 --- a/src/openrct2/world/MapAnimation.cpp +++ b/src/openrct2/world/MapAnimation.cpp @@ -131,7 +131,7 @@ static bool map_animation_invalidate_queue_banner(int32_t x, int32_t y, int32_t continue; if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH) continue; - if (!(tileElement->flags & 1)) + if (!(tileElement->AsPath()->IsQueue())) continue; if (!tileElement->AsPath()->HasQueueBanner()) continue; diff --git a/src/openrct2/world/MapGen.cpp b/src/openrct2/world/MapGen.cpp index d9dd688859..8b37ff45b9 100644 --- a/src/openrct2/world/MapGen.cpp +++ b/src/openrct2/world/MapGen.cpp @@ -237,7 +237,7 @@ static void mapgen_place_tree(int32_t type, int32_t x, int32_t y) } surfaceZ = tile_element_height({ x * 32 + 16, y * 32 + 16 }) / 8; - tileElement = tile_element_insert({ x, y, surfaceZ }, (1 | 2 | 4 | 8)); + tileElement = tile_element_insert({ x, y, surfaceZ }, 0b1111); assert(tileElement != nullptr); tileElement->clearance_height = surfaceZ + (sceneryEntry->small_scenery.height >> 3); tileElement->SetType(TILE_ELEMENT_TYPE_SMALL_SCENERY); diff --git a/src/openrct2/world/Scenery.cpp b/src/openrct2/world/Scenery.cpp index 0bd691cc8c..9114aa3cfb 100644 --- a/src/openrct2/world/Scenery.cpp +++ b/src/openrct2/world/Scenery.cpp @@ -137,7 +137,8 @@ void scenery_update_age(int32_t x, int32_t y, TileElement* tileElement) // Check map elements above, presumably to see if map element is blocked from rain tileElementAbove = tileElement; - while (!(tileElementAbove->flags & 7)) + // Change from original: RCT2 only checked for the first three quadrants, which was very likely to be a bug. + while (!(tileElementAbove->GetOccupiedQuadrants())) { tileElementAbove++; diff --git a/src/openrct2/world/TileElement.cpp b/src/openrct2/world/TileElement.cpp index 9e05815f5f..a9c75c643a 100644 --- a/src/openrct2/world/TileElement.cpp +++ b/src/openrct2/world/TileElement.cpp @@ -49,6 +49,14 @@ bool TileElementBase::IsLastForTile() const return (this->flags & TILE_ELEMENT_FLAG_LAST_TILE) != 0; } +void TileElementBase::SetLastForTile(bool on) +{ + if (on) + flags |= TILE_ELEMENT_FLAG_LAST_TILE; + else + flags &= ~TILE_ELEMENT_FLAG_LAST_TILE; +} + bool TileElementBase::IsGhost() const { return (this->flags & TILE_ELEMENT_FLAG_GHOST) != 0; @@ -154,6 +162,7 @@ void TileElement::ClearAs(uint8_t newType) base_height = 2; clearance_height = 2; std::fill_n(pad_04, sizeof(pad_04), 0x00); + std::fill_n(pad_08, sizeof(pad_08), 0x00); } void TileElementBase::Remove() @@ -204,3 +213,14 @@ const QuarterTile QuarterTile::Rotate(uint8_t amount) const return QuarterTile{ 0 }; } } + +uint8_t TileElementBase::GetOccupiedQuadrants() const +{ + return flags & TILE_ELEMENT_OCCUPIED_QUADRANTS_MASK; +} + +void TileElementBase::SetOccupiedQuadrants(uint8_t quadrants) +{ + flags &= ~TILE_ELEMENT_OCCUPIED_QUADRANTS_MASK; + flags |= (quadrants & TILE_ELEMENT_OCCUPIED_QUADRANTS_MASK); +} diff --git a/src/openrct2/world/TileElement.h b/src/openrct2/world/TileElement.h index cf25092a6b..f7f2acd843 100644 --- a/src/openrct2/world/TileElement.h +++ b/src/openrct2/world/TileElement.h @@ -61,7 +61,7 @@ struct CorruptElement; struct TileElementBase { uint8_t type; // 0 - uint8_t flags; // 1 + uint8_t flags; // 1. Upper nibble: flags. Lower nibble: occupied quadrants (one bit per quadrant). uint8_t base_height; // 2 uint8_t clearance_height; // 3 @@ -71,9 +71,12 @@ struct TileElementBase void SetDirection(uint8_t direction); uint8_t GetDirectionWithOffset(uint8_t offset) const; bool IsLastForTile() const; + void SetLastForTile(bool on); bool IsGhost() const; void SetGhost(bool isGhost); void Remove(); + uint8_t GetOccupiedQuadrants() const; + void SetOccupiedQuadrants(uint8_t quadrants); }; /** @@ -123,10 +126,6 @@ public: { return as(); } - CorruptElement* AsCorrupt() const - { - return as(); - } void ClearAs(uint8_t newType); }; @@ -246,8 +245,6 @@ public: uint8_t GetAdditionStatus() const; void SetAdditionStatus(uint8_t newStatus); - uint8_t GetRCT1PathType() const; - bool ShouldDrawPathOverSupports(); void SetShouldDrawPathOverSupports(bool on); }; @@ -604,6 +601,7 @@ enum #define TILE_ELEMENT_QUADRANT_MASK 0b11000000 #define TILE_ELEMENT_TYPE_MASK 0b00111100 #define TILE_ELEMENT_DIRECTION_MASK 0b00000011 +#define TILE_ELEMENT_OCCUPIED_QUADRANTS_MASK 0b00001111 #define TILE_ELEMENT_COLOUR_MASK 0b00011111 diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index e40676e139..5ab3d30b73 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -65,8 +65,8 @@ static bool map_swap_elements_at(CoordsXY loc, int16_t first, int16_t second) // Swap the 'last map element for tile' flag if either one of them was last if ((firstElement)->IsLastForTile() || (secondElement)->IsLastForTile()) { - firstElement->flags ^= TILE_ELEMENT_FLAG_LAST_TILE; - secondElement->flags ^= TILE_ELEMENT_FLAG_LAST_TILE; + firstElement->SetLastForTile(!firstElement->IsLastForTile()); + secondElement->SetLastForTile(!secondElement->IsLastForTile()); } return true; @@ -89,7 +89,7 @@ GameActionResult::Ptr tile_inspector_insert_corrupt_at(CoordsXY loc, int16_t ele { // Create new corrupt element TileElement* corruptElement = tile_element_insert( - { loc.x / 32, loc.y / 32, -1 }, 0); // Ugly hack: -1 guarantees this to be placed first + { loc.x / 32, loc.y / 32, -1 }, 0b0000); // Ugly hack: -1 guarantees this to be placed first if (corruptElement == nullptr) { log_warning("Failed to insert corrupt element."); @@ -320,15 +320,13 @@ GameActionResult::Ptr tile_inspector_paste_element_at(CoordsXY loc, TileElement tile_element_set_banner_index(&element, newBannerIndex); } - TileElement* const pastedElement = tile_element_insert({ loc.x / 32, loc.y / 32, element.base_height }, 0); + // The occupiedQuadrants will be automatically set when the element is copied over, so it's not necessary to set them + // correctly _here_. + TileElement* const pastedElement = tile_element_insert({ loc.x / 32, loc.y / 32, element.base_height }, 0b0000); bool lastForTile = pastedElement->IsLastForTile(); *pastedElement = element; - pastedElement->flags &= ~TILE_ELEMENT_FLAG_LAST_TILE; - if (lastForTile) - { - pastedElement->flags |= TILE_ELEMENT_FLAG_LAST_TILE; - } + pastedElement->SetLastForTile(lastForTile); map_invalidate_tile_full(loc.x, loc.y); @@ -1004,8 +1002,7 @@ GameActionResult::Ptr tile_inspector_scenery_set_quarter_location( tileElement->AsSmallScenery()->SetSceneryQuadrant(quarterIndex); // Update collision - tileElement->flags &= 0xF0; - tileElement->flags |= 1 << ((quarterIndex + 2) & 3); + tileElement->SetOccupiedQuadrants(1 << ((quarterIndex + 2) & 3)); map_invalidate_tile_full(loc.x, loc.y); if ((uint32_t)(loc.x / 32) == windowTileInspectorTileX && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) @@ -1027,7 +1024,9 @@ GameActionResult::Ptr tile_inspector_scenery_set_quarter_collision( if (isExecuting) { - tileElement->flags ^= 1 << quarterIndex; + auto occupiedQuadrants = tileElement->GetOccupiedQuadrants(); + occupiedQuadrants ^= 1 << quarterIndex; + tileElement->SetOccupiedQuadrants(occupiedQuadrants); map_invalidate_tile_full(loc.x, loc.y); if ((uint32_t)(loc.x / 32) == windowTileInspectorTileX && (uint32_t)(loc.y / 32) == windowTileInspectorTileY) diff --git a/test/testpaint/Compat.cpp b/test/testpaint/Compat.cpp index 35fae2e08d..a7f2c3c4e2 100644 --- a/test/testpaint/Compat.cpp +++ b/test/testpaint/Compat.cpp @@ -160,6 +160,14 @@ bool TileElementBase::IsLastForTile() const return (this->flags & TILE_ELEMENT_FLAG_LAST_TILE) != 0; } +void TileElementBase::SetLastForTile(bool on) +{ + if (on) + flags |= TILE_ELEMENT_FLAG_LAST_TILE; + else + flags &= ~TILE_ELEMENT_FLAG_LAST_TILE; +} + uint8_t TileElementBase::GetType() const { return this->type & TILE_ELEMENT_TYPE_MASK; @@ -441,3 +449,14 @@ bool rct_vehicle::IsGhost() const auto r = get_ride(ride); return r != nullptr && r->status == RIDE_STATUS_SIMULATING; } + +uint8_t TileElementBase::GetOccupiedQuadrants() const +{ + return flags & TILE_ELEMENT_OCCUPIED_QUADRANTS_MASK; +} + +void TileElementBase::SetOccupiedQuadrants(uint8_t quadrants) +{ + flags &= ~TILE_ELEMENT_OCCUPIED_QUADRANTS_MASK; + flags |= (quadrants & TILE_ELEMENT_OCCUPIED_QUADRANTS_MASK); +} diff --git a/test/testpaint/TestTrack.cpp b/test/testpaint/TestTrack.cpp index 13617be7dd..a97cd823dc 100644 --- a/test/testpaint/TestTrack.cpp +++ b/test/testpaint/TestTrack.cpp @@ -101,14 +101,7 @@ public: uint8_t rideType, uint8_t trackType, int variant, TileElement* tileElement, TileElement* surfaceElement, Ride* ride, rct_ride_entry* rideEntry) override { - if (variant == 0) - { - tileElement->type &= ~TRACK_ELEMENT_TYPE_FLAG_CHAIN_LIFT; - } - else - { - tileElement->type |= TRACK_ELEMENT_TYPE_FLAG_CHAIN_LIFT; - } + tileElement->AsTrack()->SetHasChain(variant != 0); } }; @@ -269,13 +262,13 @@ static uint8_t TestTrackElementPaintCalls(uint8_t rideType, uint8_t trackType, u TileElement tileElement = {}; tileElement.SetType(TILE_ELEMENT_TYPE_TRACK); - tileElement.flags |= TILE_ELEMENT_FLAG_LAST_TILE; + tileElement.SetLastForTile(true); tileElement.AsTrack()->SetTrackType(trackType); tileElement.base_height = height / 16; g_currently_drawn_item = &tileElement; TileElement surfaceElement = {}; - surfaceElement.type = TILE_ELEMENT_TYPE_SURFACE; + surfaceElement.SetType(TILE_ELEMENT_TYPE_SURFACE); surfaceElement.base_height = 2; gSurfaceElement = &surfaceElement; gDidPassSurface = true; @@ -432,13 +425,13 @@ static uint8_t TestTrackElementSegmentSupportHeight( TileElement tileElement = {}; tileElement.SetType(TILE_ELEMENT_TYPE_TRACK); - tileElement.flags |= TILE_ELEMENT_FLAG_LAST_TILE; + tileElement.SetLastForTile(true); tileElement.AsTrack()->SetTrackType(trackType); tileElement.base_height = height / 16; g_currently_drawn_item = &tileElement; TileElement surfaceElement = {}; - surfaceElement.type = TILE_ELEMENT_TYPE_SURFACE; + surfaceElement.SetType(TILE_ELEMENT_TYPE_SURFACE); surfaceElement.base_height = 2; gSurfaceElement = &surfaceElement; gDidPassSurface = true; @@ -519,13 +512,13 @@ static uint8_t TestTrackElementGeneralSupportHeight( TileElement tileElement = {}; tileElement.SetType(TILE_ELEMENT_TYPE_TRACK); - tileElement.flags |= TILE_ELEMENT_FLAG_LAST_TILE; + tileElement.SetLastForTile(true); tileElement.AsTrack()->SetTrackType(trackType); tileElement.base_height = height / 16; g_currently_drawn_item = &tileElement; TileElement surfaceElement = {}; - surfaceElement.type = TILE_ELEMENT_TYPE_SURFACE; + surfaceElement.SetType(TILE_ELEMENT_TYPE_SURFACE); surfaceElement.base_height = 2; gSurfaceElement = &surfaceElement; gDidPassSurface = true; @@ -620,13 +613,13 @@ static uint8_t TestTrackElementSideTunnels(uint8_t rideType, uint8_t trackType, TileElement tileElement = {}; tileElement.SetType(TILE_ELEMENT_TYPE_TRACK); - tileElement.flags |= TILE_ELEMENT_FLAG_LAST_TILE; + tileElement.SetLastForTile(true); tileElement.AsTrack()->SetTrackType(trackType); tileElement.base_height = height / 16; g_currently_drawn_item = &tileElement; TileElement surfaceElement = {}; - surfaceElement.type = TILE_ELEMENT_TYPE_SURFACE; + surfaceElement.SetType(TILE_ELEMENT_TYPE_SURFACE); surfaceElement.base_height = 2; gSurfaceElement = &surfaceElement; gDidPassSurface = true; @@ -748,13 +741,13 @@ static uint8_t TestTrackElementVerticalTunnels(uint8_t rideType, uint8_t trackTy TileElement tileElement = {}; tileElement.SetType(TILE_ELEMENT_TYPE_TRACK); - tileElement.flags |= TILE_ELEMENT_FLAG_LAST_TILE; + tileElement.SetLastForTile(true); tileElement.AsTrack()->SetTrackType(trackType); tileElement.base_height = height / 16; g_currently_drawn_item = &tileElement; TileElement surfaceElement = {}; - surfaceElement.type = TILE_ELEMENT_TYPE_SURFACE; + surfaceElement.SetType(TILE_ELEMENT_TYPE_SURFACE); surfaceElement.base_height = 2; gSurfaceElement = &surfaceElement; gDidPassSurface = true; diff --git a/test/testpaint/generate.cpp b/test/testpaint/generate.cpp index 28cd40dfee..1ef2cf8ba9 100644 --- a/test/testpaint/generate.cpp +++ b/test/testpaint/generate.cpp @@ -446,7 +446,7 @@ private: { TileElement tileElement = {}; tileElement.SetType(TILE_ELEMENT_TYPE_TRACK); - tileElement.flags |= TILE_ELEMENT_FLAG_LAST_TILE; + tileElement.SetLastForTile(true); tileElement.AsTrack()->SetTrackType(trackType); tileElement.base_height = 3; if (_invertedTrack) @@ -482,7 +482,7 @@ private: } // Get chain lift calls - tileElement.type |= 0x80; + tileElement.AsTrack()->SetHasChain(true); PaintIntercept::ClearCalls(); CallOriginal(trackType, direction, trackSequence, height, &tileElement); numCalls = PaintIntercept::GetCalls(callBuffer);