From f365bc3cb7c9f4001f651651da8fb13e72db8265 Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Tue, 27 Aug 2019 21:12:48 +0200 Subject: [PATCH] Create getters and setters for occupied quadrant --- src/openrct2-ui/windows/RideConstruction.cpp | 2 +- src/openrct2-ui/windows/TileInspector.cpp | 9 +++++---- src/openrct2/Game.cpp | 2 +- src/openrct2/actions/BannerPlaceAction.hpp | 2 +- src/openrct2/actions/MazeSetTrackAction.hpp | 2 +- src/openrct2/actions/PlaceParkEntranceAction.hpp | 2 +- src/openrct2/actions/WallPlaceAction.hpp | 4 ++-- src/openrct2/rct12/RCT12.h | 2 +- src/openrct2/ride/TrackDesign.cpp | 2 +- src/openrct2/ride/Vehicle.cpp | 2 +- src/openrct2/world/Map.cpp | 13 ++++++++----- src/openrct2/world/Map.h | 2 +- src/openrct2/world/MapAnimation.cpp | 1 + src/openrct2/world/MapGen.cpp | 2 +- src/openrct2/world/Scenery.cpp | 3 ++- src/openrct2/world/TileElement.cpp | 11 +++++++++++ src/openrct2/world/TileElement.h | 5 ++++- src/openrct2/world/TileInspector.cpp | 13 ++++++++----- test/testpaint/Compat.cpp | 11 +++++++++++ 19 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index 1eaaf10e7c..8347652e9d 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -2453,7 +2453,7 @@ static void sub_6CBCE2( _tempTrackTileElement.SetType(TILE_ELEMENT_TYPE_TRACK); _tempTrackTileElement.SetDirection(trackDirection); _tempTrackTileElement.AsTrack()->SetHasChain((edx & 0x10000) != 0); - _tempTrackTileElement.flags = quarterTile.GetBaseQuarterOccupied(); + _tempTrackTileElement.SetOccupiedQuadrants(quarterTile.GetBaseQuarterOccupied()); _tempTrackTileElement.SetLastForTile(true); _tempTrackTileElement.base_height = baseZ; _tempTrackTileElement.clearance_height = clearanceZ; 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..3643197511 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/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 b60d97f6dd..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); diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index 7c8762e954..b91afac957 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -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 & quadrant) + if (tileElement->GetOccupiedQuadrants() & quadrant) return tileElement; } while (!(tileElement++)->IsLastForTile()); diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 312c4213db..7eb2266367 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -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)) { @@ -1182,7 +1183,7 @@ TileElement* tile_element_insert(const TileCoordsXYZ& loc, int32_t flags) { // No more elements above the insert element (newTileElement - 1)->SetLastForTile(false); - flags |= TILE_ELEMENT_FLAG_LAST_TILE; + 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 { @@ -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 & (quarterTile.GetBaseQuarterOccupied())) + if (tileElement->GetOccupiedQuadrants() & (quarterTile.GetBaseQuarterOccupied())) { goto loc_68BABC; } diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 9b9edfb921..f4fdf3bf82 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -172,7 +172,7 @@ 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); diff --git a/src/openrct2/world/MapAnimation.cpp b/src/openrct2/world/MapAnimation.cpp index 85adc90060..081e0b7474 100644 --- a/src/openrct2/world/MapAnimation.cpp +++ b/src/openrct2/world/MapAnimation.cpp @@ -131,6 +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; + // Change from original: originally checked type instead of flags, which was likely a bug. if (!(tileElement->AsPath()->IsQueue())) continue; if (!tileElement->AsPath()->HasQueueBanner()) 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 7324e3d4de..a9c75c643a 100644 --- a/src/openrct2/world/TileElement.cpp +++ b/src/openrct2/world/TileElement.cpp @@ -213,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 d10c188763..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 @@ -75,6 +75,8 @@ struct TileElementBase bool IsGhost() const; void SetGhost(bool isGhost); void Remove(); + uint8_t GetOccupiedQuadrants() const; + void SetOccupiedQuadrants(uint8_t quadrants); }; /** @@ -599,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 a782d4ee95..5ab3d30b73 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -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,7 +320,9 @@ 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; @@ -1000,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) @@ -1023,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 3f6647a253..a7f2c3c4e2 100644 --- a/test/testpaint/Compat.cpp +++ b/test/testpaint/Compat.cpp @@ -449,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); +}