From 62a01fe043e728fa80b0963f34143025eca86393 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 19 Feb 2021 18:12:22 +0200 Subject: [PATCH 1/6] Move tile inspector code into TileInspector namespace --- src/openrct2/actions/TileModifyAction.cpp | 52 +- src/openrct2/world/TileInspector.cpp | 2064 ++++++++++----------- src/openrct2/world/TileInspector.h | 72 +- 3 files changed, 1094 insertions(+), 1094 deletions(-) diff --git a/src/openrct2/actions/TileModifyAction.cpp b/src/openrct2/actions/TileModifyAction.cpp index f3d99c142d..c2607053a5 100644 --- a/src/openrct2/actions/TileModifyAction.cpp +++ b/src/openrct2/actions/TileModifyAction.cpp @@ -11,6 +11,8 @@ #include "../world/TileInspector.h" +using namespace OpenRCT2; + TileModifyAction::TileModifyAction( CoordsXY loc, TileModifyType setting, uint32_t value1, uint32_t value2, TileElement pasteElement) : _loc(loc) @@ -55,163 +57,163 @@ GameActions::Result::Ptr TileModifyAction::QueryExecute(bool isExecuting) const case TileModifyType::AnyRemove: { const auto elementIndex = _value1; - res = tile_inspector_remove_element_at(_loc, elementIndex, isExecuting); + res = TileInspector::RemoveElementAt(_loc, elementIndex, isExecuting); break; } case TileModifyType::AnySwap: { const auto firstIndex = _value1; const auto secondIndex = _value2; - res = tile_inspector_swap_elements_at(_loc, firstIndex, secondIndex, isExecuting); + res = TileInspector::SwapElementsAt(_loc, firstIndex, secondIndex, isExecuting); break; } case TileModifyType::AnyInsertCorrupt: { const auto elementIndex = _value1; - res = tile_inspector_insert_corrupt_at(_loc, elementIndex, isExecuting); + res = TileInspector::InsertCorruptElementAt(_loc, elementIndex, isExecuting); break; } case TileModifyType::AnyRotate: { const auto elementIndex = _value1; - res = tile_inspector_rotate_element_at(_loc, elementIndex, isExecuting); + res = TileInspector::RotateElementAt(_loc, elementIndex, isExecuting); break; } case TileModifyType::AnyPaste: { - res = tile_inspector_paste_element_at(_loc, _pasteElement, isExecuting); + res = TileInspector::PasteElementAt(_loc, _pasteElement, isExecuting); break; } case TileModifyType::AnySort: { - res = tile_inspector_sort_elements_at(_loc, isExecuting); + res = TileInspector::SortElementsAt(_loc, isExecuting); break; } case TileModifyType::AnyBaseHeightOffset: { const auto elementIndex = _value1; const auto heightOffset = _value2; - res = tile_inspector_any_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); + res = TileInspector::AnyBaseHeightOffset(_loc, elementIndex, heightOffset, isExecuting); break; } case TileModifyType::SurfaceShowParkFences: { const bool showFences = _value1; - res = tile_inspector_surface_show_park_fences(_loc, showFences, isExecuting); + res = TileInspector::SurfaceShowParkFences(_loc, showFences, isExecuting); break; } case TileModifyType::SurfaceToggleCorner: { const auto cornerIndex = _value1; - res = tile_inspector_surface_toggle_corner(_loc, cornerIndex, isExecuting); + res = TileInspector::SurfaceToggleCorner(_loc, cornerIndex, isExecuting); break; } case TileModifyType::SurfaceToggleDiagonal: { - res = tile_inspector_surface_toggle_diagonal(_loc, isExecuting); + res = TileInspector::SurfaceToggleDiagonal(_loc, isExecuting); break; } case TileModifyType::PathSetSlope: { const auto elementIndex = _value1; const bool sloped = _value2; - res = tile_inspector_path_set_sloped(_loc, elementIndex, sloped, isExecuting); + res = TileInspector::PathSetSloped(_loc, elementIndex, sloped, isExecuting); break; } case TileModifyType::PathSetBroken: { const auto elementIndex = _value1; const bool broken = _value2; - res = tile_inspector_path_set_broken(_loc, elementIndex, broken, isExecuting); + res = TileInspector::PathSetBroken(_loc, elementIndex, broken, isExecuting); break; } case TileModifyType::PathToggleEdge: { const auto elementIndex = _value1; const auto edgeIndex = _value2; - res = tile_inspector_path_toggle_edge(_loc, elementIndex, edgeIndex, isExecuting); + res = TileInspector::PathToggleEdge(_loc, elementIndex, edgeIndex, isExecuting); break; } case TileModifyType::EntranceMakeUsable: { const auto elementIndex = _value1; - res = tile_inspector_entrance_make_usable(_loc, elementIndex, isExecuting); + res = TileInspector::EntranceMakeUsable(_loc, elementIndex, isExecuting); break; } case TileModifyType::WallSetSlope: { const auto elementIndex = _value1; const auto slopeValue = _value2; - res = tile_inspector_wall_set_slope(_loc, elementIndex, slopeValue, isExecuting); + res = TileInspector::WallSetSlope(_loc, elementIndex, slopeValue, isExecuting); break; } case TileModifyType::WallSetAnimationFrame: { const auto elementIndex = _value1; const auto animationFrameOffset = _value2; - res = tile_inspector_wall_animation_frame_offset(_loc, elementIndex, animationFrameOffset, isExecuting); + res = TileInspector::WallAnimationFrameOffset(_loc, elementIndex, animationFrameOffset, isExecuting); break; } case TileModifyType::TrackBaseHeightOffset: { const auto elementIndex = _value1; const auto heightOffset = _value2; - res = tile_inspector_track_base_height_offset(_loc, elementIndex, heightOffset, isExecuting); + res = TileInspector::TrackBaseHeightOffset(_loc, elementIndex, heightOffset, isExecuting); break; } case TileModifyType::TrackSetChainBlock: { const auto elementIndex = _value1; const bool setChain = _value2; - res = tile_inspector_track_set_chain(_loc, elementIndex, true, setChain, isExecuting); + res = TileInspector::TrackSetChain(_loc, elementIndex, true, setChain, isExecuting); break; } case TileModifyType::TrackSetChain: { const auto elementIndex = _value1; const bool setChain = _value2; - res = tile_inspector_track_set_chain(_loc, elementIndex, false, setChain, isExecuting); + res = TileInspector::TrackSetChain(_loc, elementIndex, false, setChain, isExecuting); break; } case TileModifyType::TrackSetBlockBrake: { const auto elementIndex = _value1; const bool blockBrake = _value2; - res = tile_inspector_track_set_block_brake(_loc, elementIndex, blockBrake, isExecuting); + res = TileInspector::TrackSetBlockBrake(_loc, elementIndex, blockBrake, isExecuting); break; } case TileModifyType::TrackSetIndestructible: { const auto elementIndex = _value1; const bool isIndestructible = _value2; - res = tile_inspector_track_set_indestructible(_loc, elementIndex, isIndestructible, isExecuting); + res = TileInspector::TrackSetIndestructible(_loc, elementIndex, isIndestructible, isExecuting); break; } case TileModifyType::ScenerySetQuarterLocation: { const auto elementIndex = _value1; const auto quarterIndex = _value2; - res = tile_inspector_scenery_set_quarter_location(_loc, elementIndex, quarterIndex, isExecuting); + res = TileInspector::ScenerySetQuarterLocation(_loc, elementIndex, quarterIndex, isExecuting); break; } case TileModifyType::ScenerySetQuarterCollision: { const auto elementIndex = _value1; const auto quarterIndex = _value2; - res = tile_inspector_scenery_set_quarter_collision(_loc, elementIndex, quarterIndex, isExecuting); + res = TileInspector::ScenerySetQuarterCollision(_loc, elementIndex, quarterIndex, isExecuting); break; } case TileModifyType::BannerToggleBlockingEdge: { const auto elementIndex = _value1; const auto edgeIndex = _value2; - res = tile_inspector_banner_toggle_blocking_edge(_loc, elementIndex, edgeIndex, isExecuting); + res = TileInspector::BannerToggleBlockingEdge(_loc, elementIndex, edgeIndex, isExecuting); break; } case TileModifyType::CorruptClamp: { const auto elementIndex = _value1; - res = tile_inspector_corrupt_clamp(_loc, elementIndex, isExecuting); + res = TileInspector::CorruptClamp(_loc, elementIndex, isExecuting); break; } default: diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index 28dbe29dca..d5d7cb41a8 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -30,1162 +30,1160 @@ #include "Scenery.h" #include "Surface.h" -using namespace OpenRCT2; - TileCoordsXY windowTileInspectorTile; int32_t windowTileInspectorElementCount = 0; int32_t windowTileInspectorSelectedIndex; -static bool map_swap_elements_at(const CoordsXY& loc, int16_t first, int16_t second) +namespace OpenRCT2::TileInspector { - TileElement* const firstElement = map_get_nth_element_at(loc, first); - TileElement* const secondElement = map_get_nth_element_at(loc, second); - - if (firstElement == nullptr) + static bool map_swap_elements_at(const CoordsXY& loc, int16_t first, int16_t second) { - log_error("First element is out of range for the tile"); - return false; - } - if (secondElement == nullptr) - { - log_error("Second element is out of range for the tile"); - return false; - } - if (firstElement == secondElement) - { - log_error("Can't swap the element with itself"); - return false; - } + TileElement* const firstElement = map_get_nth_element_at(loc, first); + TileElement* const secondElement = map_get_nth_element_at(loc, second); - // Swap their memory - TileElement temp = *firstElement; - *firstElement = *secondElement; - *secondElement = temp; - - // Swap the 'last map element for tile' flag if either one of them was last - if ((firstElement)->IsLastForTile() || (secondElement)->IsLastForTile()) - { - firstElement->SetLastForTile(!firstElement->IsLastForTile()); - secondElement->SetLastForTile(!secondElement->IsLastForTile()); - } - - return true; -} - -/** - * Inserts a corrupt element under a given element on a given tile - * @param x The x coordinate of the tile - * @param y The y coordinate of the tile - * @param elementIndex The nth element on this tile - * Returns 0 on success, MONEY_UNDEFINED otherwise. - */ -GameActionResultPtr tile_inspector_insert_corrupt_at(const CoordsXY& loc, int16_t elementIndex, bool isExecuting) -{ - // Make sure there is enough space for the new element - if (!map_check_free_elements_and_reorganise(1)) - return std::make_unique(GameActions::Status::NoFreeElements, STR_NONE); - - if (isExecuting) - { - // Create new corrupt element - TileElement* corruptElement = tile_element_insert( - { loc, (-1 * COORDS_Z_STEP) }, 0b0000, - TileElementType::Corrupt); // Ugly hack: -1 guarantees this to be placed first - if (corruptElement == nullptr) + if (firstElement == nullptr) { - log_warning("Failed to insert corrupt element."); - return std::make_unique(GameActions::Status::Unknown, STR_NONE); + log_error("First element is out of range for the tile"); + return false; + } + if (secondElement == nullptr) + { + log_error("Second element is out of range for the tile"); + return false; + } + if (firstElement == secondElement) + { + log_error("Can't swap the element with itself"); + return false; } - // Set the base height to be the same as the selected element - TileElement* const selectedElement = map_get_nth_element_at(loc, elementIndex + 1); - if (selectedElement == nullptr) - { - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - } - corruptElement->base_height = corruptElement->clearance_height = selectedElement->base_height; + // Swap their memory + TileElement temp = *firstElement; + *firstElement = *secondElement; + *secondElement = temp; - // Move the corrupt element up until the selected list item is reached - // this way it's placed under the selected element, even when there are multiple elements with the same base height - for (int16_t i = 0; i < elementIndex; i++) + // Swap the 'last map element for tile' flag if either one of them was last + if ((firstElement)->IsLastForTile() || (secondElement)->IsLastForTile()) { - if (!map_swap_elements_at(loc, i, i + 1)) + firstElement->SetLastForTile(!firstElement->IsLastForTile()); + secondElement->SetLastForTile(!secondElement->IsLastForTile()); + } + + return true; + } + + /** + * Inserts a corrupt element under a given element on a given tile + * @param x The x coordinate of the tile + * @param y The y coordinate of the tile + * @param elementIndex The nth element on this tile + * Returns 0 on success, MONEY_UNDEFINED otherwise. + */ + GameActionResultPtr InsertCorruptElementAt(const CoordsXY& loc, int16_t elementIndex, bool isExecuting) + { + // Make sure there is enough space for the new element + if (!map_check_free_elements_and_reorganise(1)) + return std::make_unique(GameActions::Status::NoFreeElements, STR_NONE); + + if (isExecuting) + { + // Create new corrupt element + TileElement* corruptElement = tile_element_insert( + { loc, (-1 * COORDS_Z_STEP) }, 0b0000, + TileElementType::Corrupt); // Ugly hack: -1 guarantees this to be placed first + if (corruptElement == nullptr) { - // don't return error here, we've already inserted an element - // and moved it as far as we could, the only sensible thing left - // to do is to invalidate the window. - break; + log_warning("Failed to insert corrupt element."); + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + } + + // Set the base height to be the same as the selected element + TileElement* const selectedElement = map_get_nth_element_at(loc, elementIndex + 1); + if (selectedElement == nullptr) + { + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + } + corruptElement->base_height = corruptElement->clearance_height = selectedElement->base_height; + + // Move the corrupt element up until the selected list item is reached + // this way it's placed under the selected element, even when there are multiple elements with the same base height + for (int16_t i = 0; i < elementIndex; i++) + { + if (!map_swap_elements_at(loc, i, i + 1)) + { + // don't return error here, we've already inserted an element + // and moved it as far as we could, the only sensible thing left + // to do is to invalidate the window. + break; + } + } + + map_invalidate_tile_full(loc); + + // Update the tile inspector's list for everyone who has the tile selected + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + windowTileInspectorElementCount++; + + // Keep other elements (that are not being hidden) selected + if (windowTileInspectorSelectedIndex > elementIndex) + { + windowTileInspectorSelectedIndex++; + } + + tileInspectorWindow->Invalidate(); } } - map_invalidate_tile_full(loc); + // Nothing went wrong + return std::make_unique(); + } - // Update the tile inspector's list for everyone who has the tile selected - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + static int32_t numLargeScenerySequences(const CoordsXY& loc, const LargeSceneryElement* const largeScenery) + { + const rct_scenery_entry* const largeEntry = largeScenery->GetEntry(); + const auto* const tiles = largeEntry->large_scenery.tiles; + const auto direction = largeScenery->GetDirection(); + + const auto rotatedFirstTile = CoordsXYZ{ CoordsXY{ tiles[largeScenery->GetSequenceIndex()].x_offset, + tiles[largeScenery->GetSequenceIndex()].y_offset } + .Rotate(direction), + tiles[largeScenery->GetSequenceIndex()].z_offset }; + + const auto firstTile = CoordsXYZ{ loc, largeScenery->GetBaseZ() } - rotatedFirstTile; + auto numFoundElements = 0; + for (int32_t i = 0; tiles[i].x_offset != -1; i++) { - windowTileInspectorElementCount++; + const auto rotatedCurrentTile = CoordsXYZ{ CoordsXY{ tiles[i].x_offset, tiles[i].y_offset }.Rotate(direction), + tiles[i].z_offset }; - // Keep other elements (that are not being hidden) selected - if (windowTileInspectorSelectedIndex > elementIndex) + const auto currentTile = firstTile + rotatedCurrentTile; + + const TileElement* tileElement = map_get_first_element_at(currentTile); + if (tileElement != nullptr) { - windowTileInspectorSelectedIndex++; + do + { + if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) + continue; + + if (tileElement->GetDirection() != direction) + continue; + + if (tileElement->AsLargeScenery()->GetSequenceIndex() != i) + continue; + + if (tileElement->GetBaseZ() != currentTile.z) + continue; + + numFoundElements++; + break; + } while (!(tileElement++)->IsLastForTile()); + } + } + return numFoundElements; + } + + /** + * Forcefully removes an element for a given tile + * @param x The x coordinate of the tile + * @param y The y coordinate of the tile + * @param elementIndex The nth element on this tile + */ + GameActionResultPtr RemoveElementAt(const CoordsXY& loc, int16_t elementIndex, bool isExecuting) + { + if (isExecuting) + { + // Forcefully remove the element + TileElement* const tileElement = map_get_nth_element_at(loc, elementIndex); + if (tileElement == nullptr) + { + return std::make_unique(GameActions::Status::Unknown, STR_NONE); } - tileInspectorWindow->Invalidate(); - } - } - - // Nothing went wrong - return std::make_unique(); -} - -static int32_t numLargeScenerySequences(const CoordsXY& loc, const LargeSceneryElement* const largeScenery) -{ - const rct_scenery_entry* const largeEntry = largeScenery->GetEntry(); - const auto* const tiles = largeEntry->large_scenery.tiles; - const auto direction = largeScenery->GetDirection(); - - const auto rotatedFirstTile = CoordsXYZ{ - CoordsXY{ tiles[largeScenery->GetSequenceIndex()].x_offset, tiles[largeScenery->GetSequenceIndex()].y_offset }.Rotate( - direction), - tiles[largeScenery->GetSequenceIndex()].z_offset - }; - - const auto firstTile = CoordsXYZ{ loc, largeScenery->GetBaseZ() } - rotatedFirstTile; - auto numFoundElements = 0; - for (int32_t i = 0; tiles[i].x_offset != -1; i++) - { - const auto rotatedCurrentTile = CoordsXYZ{ CoordsXY{ tiles[i].x_offset, tiles[i].y_offset }.Rotate(direction), - tiles[i].z_offset }; - - const auto currentTile = firstTile + rotatedCurrentTile; - - const TileElement* tileElement = map_get_first_element_at(currentTile); - if (tileElement != nullptr) - { - do + auto largeScenery = tileElement->AsLargeScenery(); + if (largeScenery) { - if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY) - continue; - - if (tileElement->GetDirection() != direction) - continue; - - if (tileElement->AsLargeScenery()->GetSequenceIndex() != i) - continue; - - if (tileElement->GetBaseZ() != currentTile.z) - continue; - - numFoundElements++; - break; - } while (!(tileElement++)->IsLastForTile()); - } - } - return numFoundElements; -} - -/** - * Forcefully removes an element for a given tile - * @param x The x coordinate of the tile - * @param y The y coordinate of the tile - * @param elementIndex The nth element on this tile - */ -GameActionResultPtr tile_inspector_remove_element_at(const CoordsXY& loc, int16_t elementIndex, bool isExecuting) -{ - if (isExecuting) - { - // Forcefully remove the element - TileElement* const tileElement = map_get_nth_element_at(loc, elementIndex); - if (tileElement == nullptr) - { - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - } - - auto largeScenery = tileElement->AsLargeScenery(); - if (largeScenery) - { - // Only delete the banner entry if there are no other parts of the large scenery to delete - if (numLargeScenerySequences(loc, largeScenery) == 1) + // Only delete the banner entry if there are no other parts of the large scenery to delete + if (numLargeScenerySequences(loc, largeScenery) == 1) + { + tileElement->RemoveBannerEntry(); + } + } + else { + // Removes any potential banners from the entry tileElement->RemoveBannerEntry(); } - } - else - { - // Removes any potential banners from the entry - tileElement->RemoveBannerEntry(); - } - tile_element_remove(tileElement); - map_invalidate_tile_full(loc); + tile_element_remove(tileElement); + map_invalidate_tile_full(loc); - // Update the window - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - windowTileInspectorElementCount--; - - if (windowTileInspectorSelectedIndex > elementIndex) + // Update the window + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { - windowTileInspectorSelectedIndex--; + windowTileInspectorElementCount--; + + if (windowTileInspectorSelectedIndex > elementIndex) + { + windowTileInspectorSelectedIndex--; + } + else if (windowTileInspectorSelectedIndex == elementIndex) + { + windowTileInspectorSelectedIndex = -1; + } + + tileInspectorWindow->Invalidate(); } - else if (windowTileInspectorSelectedIndex == elementIndex) + } + + return std::make_unique(); + } + + GameActionResultPtr SwapElementsAt(const CoordsXY& loc, int16_t first, int16_t second, bool isExecuting) + { + if (isExecuting) + { + if (!map_swap_elements_at(loc, first, second)) + { + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + } + map_invalidate_tile_full(loc); + + // Update the window + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + // If one of them was selected, update selected list item + if (windowTileInspectorSelectedIndex == first) + windowTileInspectorSelectedIndex = second; + else if (windowTileInspectorSelectedIndex == second) + windowTileInspectorSelectedIndex = first; + + tileInspectorWindow->Invalidate(); + } + } + + return std::make_unique(); + } + + GameActionResultPtr RotateElementAt(const CoordsXY& loc, int32_t elementIndex, bool isExecuting) + { + if (isExecuting) + { + uint8_t newRotation, pathEdges, pathCorners; + + TileElement* const tileElement = map_get_nth_element_at(loc, elementIndex); + if (tileElement == nullptr) + { + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + } + switch (tileElement->GetType()) + { + case TILE_ELEMENT_TYPE_PATH: + if (tileElement->AsPath()->IsSloped()) + { + newRotation = (tileElement->AsPath()->GetSlopeDirection() + 1) & TILE_ELEMENT_DIRECTION_MASK; + tileElement->AsPath()->SetSlopeDirection(newRotation); + } + pathEdges = tileElement->AsPath()->GetEdges(); + pathCorners = tileElement->AsPath()->GetCorners(); + tileElement->AsPath()->SetEdges((pathEdges << 1) | (pathEdges >> 3)); + tileElement->AsPath()->SetCorners((pathCorners << 1) | (pathCorners >> 3)); + break; + case TILE_ELEMENT_TYPE_ENTRANCE: + { + // Update element rotation + newRotation = tileElement->GetDirectionWithOffset(1); + tileElement->SetDirection(newRotation); + + // Update ride's known entrance/exit rotation + auto ride = get_ride(tileElement->AsEntrance()->GetRideIndex()); + if (ride != nullptr) + { + auto stationIndex = tileElement->AsEntrance()->GetStationIndex(); + auto entrance = ride_get_entrance_location(ride, stationIndex); + auto exit = ride_get_exit_location(ride, stationIndex); + uint8_t entranceType = tileElement->AsEntrance()->GetEntranceType(); + uint8_t z = tileElement->base_height; + + // Make sure this is the correct entrance or exit + if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE && entrance.x == loc.x / 32 && entrance.y == loc.y / 32 + && entrance.z == z) + { + ride_set_entrance_location(ride, stationIndex, { entrance.x, entrance.y, entrance.z, newRotation }); + } + else if ( + entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit.x == loc.x / 32 && exit.y == loc.y / 32 + && exit.z == z) + { + ride_set_exit_location(ride, stationIndex, { exit.x, exit.y, exit.z, newRotation }); + } + } + break; + } + case TILE_ELEMENT_TYPE_TRACK: + case TILE_ELEMENT_TYPE_SMALL_SCENERY: + case TILE_ELEMENT_TYPE_WALL: + newRotation = tileElement->GetDirectionWithOffset(1); + tileElement->SetDirection(newRotation); + break; + case TILE_ELEMENT_TYPE_BANNER: + { + uint8_t unblockedEdges = tileElement->AsBanner()->GetAllowedEdges(); + unblockedEdges = (unblockedEdges << 1 | unblockedEdges >> 3) & 0xF; + tileElement->AsBanner()->SetAllowedEdges(unblockedEdges); + tileElement->AsBanner()->SetPosition((tileElement->AsBanner()->GetPosition() + 1) & 3); + break; + } + } + + map_invalidate_tile_full(loc); + + if (loc == windowTileInspectorTile.ToCoordsXY()) + { + window_invalidate_by_class(WC_TILE_INSPECTOR); + } + } + + return std::make_unique(); + } + + GameActionResultPtr PasteElementAt(const CoordsXY& loc, TileElement element, bool isExecuting) + { + // Make sure there is enough space for the new element + if (!map_check_free_elements_and_reorganise(1)) + { + return std::make_unique(GameActions::Status::NoFreeElements, STR_NONE); + } + + auto tileLoc = TileCoordsXY(loc); + + if (isExecuting) + { + // Check if the element to be pasted refers to a banner index + auto bannerIndex = element.GetBannerIndex(); + if (bannerIndex != BANNER_INDEX_NULL) + { + // The element to be pasted refers to a banner index - make a copy of it + auto newBannerIndex = create_new_banner(GAME_COMMAND_FLAG_APPLY); + if (newBannerIndex == BANNER_INDEX_NULL) + { + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + } + auto& newBanner = *GetBanner(newBannerIndex); + newBanner = *GetBanner(bannerIndex); + newBanner.position = tileLoc; + + // Use the new banner index + element.SetBannerIndex(newBannerIndex); + } + + // 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, element.GetBaseZ() }, 0b0000, TileElementType::Surface); + + bool lastForTile = pastedElement->IsLastForTile(); + *pastedElement = element; + pastedElement->SetLastForTile(lastForTile); + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && tileLoc == windowTileInspectorTile) + { + windowTileInspectorElementCount++; + + // Select new element if there was none selected already + int16_t newIndex = static_cast((pastedElement - map_get_first_element_at(loc))); + if (windowTileInspectorSelectedIndex == -1) + windowTileInspectorSelectedIndex = newIndex; + else if (windowTileInspectorSelectedIndex >= newIndex) + windowTileInspectorSelectedIndex++; + + tileInspectorWindow->Invalidate(); + } + } + + return std::make_unique(); + } + + GameActionResultPtr SortElementsAt(const CoordsXY& loc, bool isExecuting) + { + if (isExecuting) + { + const TileElement* const firstElement = map_get_first_element_at(loc); + if (firstElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + // Count elements on tile + int32_t numElement = 0; + const TileElement* elementIterator = firstElement; + do + { + numElement++; + } while (!(elementIterator++)->IsLastForTile()); + + // Bubble sort + for (int32_t loopStart = 1; loopStart < numElement; loopStart++) + { + int32_t currentId = loopStart; + const TileElement* currentElement = firstElement + currentId; + const TileElement* otherElement = currentElement - 1; + + // While current element's base height is lower, or (when their baseheight is the same) the other map element's + // clearance height is lower... + while (currentId > 0 + && (otherElement->base_height > currentElement->base_height + || (otherElement->base_height == currentElement->base_height + && otherElement->clearance_height > currentElement->clearance_height))) + { + if (!map_swap_elements_at(loc, currentId - 1, currentId)) + { + // don't return error here, we've already ran some actions + // and moved things as far as we could, the only sensible + // thing left to do is to invalidate the window. + loopStart = numElement; + break; + } + currentId--; + currentElement--; + otherElement--; + } + } + + map_invalidate_tile_full(loc); + + // Deselect tile for clients who had it selected + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { windowTileInspectorSelectedIndex = -1; + tileInspectorWindow->Invalidate(); } - - tileInspectorWindow->Invalidate(); } + + return std::make_unique(); } - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_swap_elements_at(const CoordsXY& loc, int16_t first, int16_t second, bool isExecuting) -{ - if (isExecuting) + static GameActionResultPtr ValidateTileHeight(TileElement* const tileElement, int8_t heightOffset) { - if (!map_swap_elements_at(loc, first, second)) + int16_t newBaseHeight = static_cast(tileElement->base_height + heightOffset); + int16_t newClearanceHeight = static_cast(tileElement->clearance_height + heightOffset); + if (newBaseHeight < 0) { - return std::make_unique(GameActions::Status::Unknown, STR_NONE); + return std::make_unique(GameActions::Status::TooLow, STR_CANT_LOWER_ELEMENT_HERE, STR_TOO_LOW); } - map_invalidate_tile_full(loc); - - // Update the window - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + else if (newBaseHeight > MAX_ELEMENT_HEIGHT) { - // If one of them was selected, update selected list item - if (windowTileInspectorSelectedIndex == first) - windowTileInspectorSelectedIndex = second; - else if (windowTileInspectorSelectedIndex == second) - windowTileInspectorSelectedIndex = first; - - tileInspectorWindow->Invalidate(); + return std::make_unique( + GameActions::Status::TooHigh, STR_CANT_RAISE_ELEMENT_HERE, STR_TOO_HIGH); } + else if (newClearanceHeight < 0) + { + return std::make_unique( + GameActions::Status::NoClearance, STR_CANT_LOWER_ELEMENT_HERE, STR_NO_CLEARANCE); + } + else if (newClearanceHeight > MAX_ELEMENT_HEIGHT) + { + return std::make_unique( + GameActions::Status::NoClearance, STR_CANT_RAISE_ELEMENT_HERE, STR_NO_CLEARANCE); + } + return std::make_unique(); } - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_rotate_element_at(const CoordsXY& loc, int32_t elementIndex, bool isExecuting) -{ - if (isExecuting) + GameActionResultPtr AnyBaseHeightOffset(const CoordsXY& loc, int16_t elementIndex, int8_t heightOffset, bool isExecuting) { - uint8_t newRotation, pathEdges, pathCorners; - TileElement* const tileElement = map_get_nth_element_at(loc, elementIndex); if (tileElement == nullptr) - { - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - } - switch (tileElement->GetType()) - { - case TILE_ELEMENT_TYPE_PATH: - if (tileElement->AsPath()->IsSloped()) - { - newRotation = (tileElement->AsPath()->GetSlopeDirection() + 1) & TILE_ELEMENT_DIRECTION_MASK; - tileElement->AsPath()->SetSlopeDirection(newRotation); - } - pathEdges = tileElement->AsPath()->GetEdges(); - pathCorners = tileElement->AsPath()->GetCorners(); - tileElement->AsPath()->SetEdges((pathEdges << 1) | (pathEdges >> 3)); - tileElement->AsPath()->SetCorners((pathCorners << 1) | (pathCorners >> 3)); - break; - case TILE_ELEMENT_TYPE_ENTRANCE: - { - // Update element rotation - newRotation = tileElement->GetDirectionWithOffset(1); - tileElement->SetDirection(newRotation); - - // Update ride's known entrance/exit rotation - auto ride = get_ride(tileElement->AsEntrance()->GetRideIndex()); - if (ride != nullptr) - { - auto stationIndex = tileElement->AsEntrance()->GetStationIndex(); - auto entrance = ride_get_entrance_location(ride, stationIndex); - auto exit = ride_get_exit_location(ride, stationIndex); - uint8_t entranceType = tileElement->AsEntrance()->GetEntranceType(); - uint8_t z = tileElement->base_height; - - // Make sure this is the correct entrance or exit - if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE && entrance.x == loc.x / 32 && entrance.y == loc.y / 32 - && entrance.z == z) - { - ride_set_entrance_location(ride, stationIndex, { entrance.x, entrance.y, entrance.z, newRotation }); - } - else if ( - entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit.x == loc.x / 32 && exit.y == loc.y / 32 && exit.z == z) - { - ride_set_exit_location(ride, stationIndex, { exit.x, exit.y, exit.z, newRotation }); - } - } - break; - } - case TILE_ELEMENT_TYPE_TRACK: - case TILE_ELEMENT_TYPE_SMALL_SCENERY: - case TILE_ELEMENT_TYPE_WALL: - newRotation = tileElement->GetDirectionWithOffset(1); - tileElement->SetDirection(newRotation); - break; - case TILE_ELEMENT_TYPE_BANNER: - { - uint8_t unblockedEdges = tileElement->AsBanner()->GetAllowedEdges(); - unblockedEdges = (unblockedEdges << 1 | unblockedEdges >> 3) & 0xF; - tileElement->AsBanner()->SetAllowedEdges(unblockedEdges); - tileElement->AsBanner()->SetPosition((tileElement->AsBanner()->GetPosition() + 1) & 3); - break; - } - } - - map_invalidate_tile_full(loc); - - if (loc == windowTileInspectorTile.ToCoordsXY()) - { - window_invalidate_by_class(WC_TILE_INSPECTOR); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_paste_element_at(const CoordsXY& loc, TileElement element, bool isExecuting) -{ - // Make sure there is enough space for the new element - if (!map_check_free_elements_and_reorganise(1)) - { - return std::make_unique(GameActions::Status::NoFreeElements, STR_NONE); - } - - auto tileLoc = TileCoordsXY(loc); - - if (isExecuting) - { - // Check if the element to be pasted refers to a banner index - auto bannerIndex = element.GetBannerIndex(); - if (bannerIndex != BANNER_INDEX_NULL) - { - // The element to be pasted refers to a banner index - make a copy of it - auto newBannerIndex = create_new_banner(GAME_COMMAND_FLAG_APPLY); - if (newBannerIndex == BANNER_INDEX_NULL) - { - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - } - auto& newBanner = *GetBanner(newBannerIndex); - newBanner = *GetBanner(bannerIndex); - newBanner.position = tileLoc; - - // Use the new banner index - element.SetBannerIndex(newBannerIndex); - } - - // 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, element.GetBaseZ() }, 0b0000, TileElementType::Surface); - - bool lastForTile = pastedElement->IsLastForTile(); - *pastedElement = element; - pastedElement->SetLastForTile(lastForTile); - - map_invalidate_tile_full(loc); - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && tileLoc == windowTileInspectorTile) - { - windowTileInspectorElementCount++; - - // Select new element if there was none selected already - int16_t newIndex = static_cast((pastedElement - map_get_first_element_at(loc))); - if (windowTileInspectorSelectedIndex == -1) - windowTileInspectorSelectedIndex = newIndex; - else if (windowTileInspectorSelectedIndex >= newIndex) - windowTileInspectorSelectedIndex++; - - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_sort_elements_at(const CoordsXY& loc, bool isExecuting) -{ - if (isExecuting) - { - const TileElement* const firstElement = map_get_first_element_at(loc); - if (firstElement == nullptr) return std::make_unique(GameActions::Status::Unknown, STR_NONE); - // Count elements on tile - int32_t numElement = 0; - const TileElement* elementIterator = firstElement; - do - { - numElement++; - } while (!(elementIterator++)->IsLastForTile()); + auto heightValidationResult = ValidateTileHeight(tileElement, heightOffset); + if (heightValidationResult->Error != GameActions::Status::Ok) + return heightValidationResult; - // Bubble sort - for (int32_t loopStart = 1; loopStart < numElement; loopStart++) + if (isExecuting) { - int32_t currentId = loopStart; - const TileElement* currentElement = firstElement + currentId; - const TileElement* otherElement = currentElement - 1; - - // While current element's base height is lower, or (when their baseheight is the same) the other map element's - // clearance height is lower... - while (currentId > 0 - && (otherElement->base_height > currentElement->base_height - || (otherElement->base_height == currentElement->base_height - && otherElement->clearance_height > currentElement->clearance_height))) + if (tileElement->GetType() == TILE_ELEMENT_TYPE_ENTRANCE) { - if (!map_swap_elements_at(loc, currentId - 1, currentId)) + uint8_t entranceType = tileElement->AsEntrance()->GetEntranceType(); + if (entranceType != ENTRANCE_TYPE_PARK_ENTRANCE) { - // don't return error here, we've already ran some actions - // and moved things as far as we could, the only sensible - // thing left to do is to invalidate the window. - loopStart = numElement; - break; + // Update the ride's known entrance or exit height + auto ride = get_ride(tileElement->AsEntrance()->GetRideIndex()); + if (ride != nullptr) + { + auto entranceIndex = tileElement->AsEntrance()->GetStationIndex(); + auto entrance = ride_get_entrance_location(ride, entranceIndex); + auto exit = ride_get_exit_location(ride, entranceIndex); + uint8_t z = tileElement->base_height; + + // Make sure this is the correct entrance or exit + if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE && entrance == TileCoordsXYZ{ loc, z }) + ride_set_entrance_location( + ride, entranceIndex, { entrance.x, entrance.y, z + heightOffset, entrance.direction }); + else if (entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit == TileCoordsXYZ{ loc, z }) + ride_set_exit_location(ride, entranceIndex, { exit.x, exit.y, z + heightOffset, exit.direction }); + } } - currentId--; - currentElement--; - otherElement--; + } + + tileElement->base_height += heightOffset; + tileElement->clearance_height += heightOffset; + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); } } - map_invalidate_tile_full(loc); - - // Deselect tile for clients who had it selected - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - windowTileInspectorSelectedIndex = -1; - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -static GameActionResultPtr ValidateTileHeight(TileElement* const tileElement, int8_t heightOffset) -{ - int16_t newBaseHeight = static_cast(tileElement->base_height + heightOffset); - int16_t newClearanceHeight = static_cast(tileElement->clearance_height + heightOffset); - if (newBaseHeight < 0) - { - return std::make_unique(GameActions::Status::TooLow, STR_CANT_LOWER_ELEMENT_HERE, STR_TOO_LOW); - } - else if (newBaseHeight > MAX_ELEMENT_HEIGHT) - { - return std::make_unique(GameActions::Status::TooHigh, STR_CANT_RAISE_ELEMENT_HERE, STR_TOO_HIGH); - } - else if (newClearanceHeight < 0) - { - return std::make_unique( - GameActions::Status::NoClearance, STR_CANT_LOWER_ELEMENT_HERE, STR_NO_CLEARANCE); - } - else if (newClearanceHeight > MAX_ELEMENT_HEIGHT) - { - return std::make_unique( - GameActions::Status::NoClearance, STR_CANT_RAISE_ELEMENT_HERE, STR_NO_CLEARANCE); - } - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_any_base_height_offset( - const CoordsXY& loc, int16_t elementIndex, int8_t heightOffset, bool isExecuting) -{ - TileElement* const tileElement = map_get_nth_element_at(loc, elementIndex); - if (tileElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - auto heightValidationResult = ValidateTileHeight(tileElement, heightOffset); - if (heightValidationResult->Error != GameActions::Status::Ok) - return heightValidationResult; - - if (isExecuting) - { - if (tileElement->GetType() == TILE_ELEMENT_TYPE_ENTRANCE) - { - uint8_t entranceType = tileElement->AsEntrance()->GetEntranceType(); - if (entranceType != ENTRANCE_TYPE_PARK_ENTRANCE) - { - // Update the ride's known entrance or exit height - auto ride = get_ride(tileElement->AsEntrance()->GetRideIndex()); - if (ride != nullptr) - { - auto entranceIndex = tileElement->AsEntrance()->GetStationIndex(); - auto entrance = ride_get_entrance_location(ride, entranceIndex); - auto exit = ride_get_exit_location(ride, entranceIndex); - uint8_t z = tileElement->base_height; - - // Make sure this is the correct entrance or exit - if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE && entrance == TileCoordsXYZ{ loc, z }) - ride_set_entrance_location( - ride, entranceIndex, { entrance.x, entrance.y, z + heightOffset, entrance.direction }); - else if (entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit == TileCoordsXYZ{ loc, z }) - ride_set_exit_location(ride, entranceIndex, { exit.x, exit.y, z + heightOffset, exit.direction }); - } - } - } - - tileElement->base_height += heightOffset; - tileElement->clearance_height += heightOffset; - - map_invalidate_tile_full(loc); - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_surface_show_park_fences(const CoordsXY& loc, bool showFences, bool isExecuting) -{ - auto* const surfaceelement = map_get_surface_element_at(loc); - - // No surface element on tile - if (surfaceelement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) - { - if (!showFences) - surfaceelement->SetParkFences(0); - else - update_park_fences(loc); - - map_invalidate_tile_full(loc); - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_surface_toggle_corner(const CoordsXY& loc, int32_t cornerIndex, bool isExecuting) -{ - auto* const surfaceElement = map_get_surface_element_at(loc); - - // No surface element on tile - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) - { - const uint8_t originalSlope = surfaceElement->GetSlope(); - const bool diagonal = (originalSlope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) >> 4; - - uint8_t newSlope = surfaceElement->GetSlope() ^ (1 << cornerIndex); - surfaceElement->SetSlope(newSlope); - if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) - { - surfaceElement->clearance_height = surfaceElement->base_height + 2; - } - else - { - surfaceElement->clearance_height = surfaceElement->base_height; - } - - // All corners are raised - if ((surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) == TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) - { - uint8_t slope = TILE_ELEMENT_SLOPE_FLAT; - - if (diagonal) - { - switch (originalSlope & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) - { - case TILE_ELEMENT_SLOPE_S_CORNER_DN: - slope |= TILE_ELEMENT_SLOPE_N_CORNER_UP; - break; - case TILE_ELEMENT_SLOPE_W_CORNER_DN: - slope |= TILE_ELEMENT_SLOPE_E_CORNER_UP; - break; - case TILE_ELEMENT_SLOPE_N_CORNER_DN: - slope |= TILE_ELEMENT_SLOPE_S_CORNER_UP; - break; - case TILE_ELEMENT_SLOPE_E_CORNER_DN: - slope |= TILE_ELEMENT_SLOPE_W_CORNER_UP; - break; - } - } - surfaceElement->SetSlope(slope); - - // Update base and clearance heights - surfaceElement->base_height += 2; - surfaceElement->clearance_height = surfaceElement->base_height + (diagonal ? 2 : 0); - } - - map_invalidate_tile_full(loc); - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_surface_toggle_diagonal(const CoordsXY& loc, bool isExecuting) -{ - auto* const surfaceElement = map_get_surface_element_at(loc); - - // No surface element on tile - if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) - { - uint8_t newSlope = surfaceElement->GetSlope() ^ TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT; - surfaceElement->SetSlope(newSlope); - if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) - { - surfaceElement->clearance_height = surfaceElement->base_height + 4; - } - else if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) - { - surfaceElement->clearance_height = surfaceElement->base_height + 2; - } - else - { - surfaceElement->clearance_height = surfaceElement->base_height; - } - - map_invalidate_tile_full(loc); - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_path_set_sloped(const CoordsXY& loc, int32_t elementIndex, bool sloped, bool isExecuting) -{ - TileElement* const pathElement = map_get_nth_element_at(loc, elementIndex); - - if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) - { - pathElement->AsPath()->SetSloped(sloped); - - map_invalidate_tile_full(loc); - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_path_set_broken(const CoordsXY& loc, int32_t elementIndex, bool broken, bool isExecuting) -{ - TileElement* const pathElement = map_get_nth_element_at(loc, elementIndex); - - if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) - { - pathElement->AsPath()->SetIsBroken(broken); - - map_invalidate_tile_full(loc); - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_path_toggle_edge( - const CoordsXY& loc, int32_t elementIndex, int32_t edgeIndex, bool isExecuting) -{ - TileElement* const pathElement = map_get_nth_element_at(loc, elementIndex); - - if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) - { - uint8_t newEdges = pathElement->AsPath()->GetEdgesAndCorners() ^ (1 << edgeIndex); - pathElement->AsPath()->SetEdgesAndCorners(newEdges); - - map_invalidate_tile_full(loc); - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_entrance_make_usable(const CoordsXY& loc, int32_t elementIndex, bool isExecuting) -{ - TileElement* const entranceElement = map_get_nth_element_at(loc, elementIndex); - - if (entranceElement == nullptr || entranceElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - auto ride = get_ride(entranceElement->AsEntrance()->GetRideIndex()); - if (ride == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) - { - auto stationIndex = entranceElement->AsEntrance()->GetStationIndex(); - - switch (entranceElement->AsEntrance()->GetEntranceType()) - { - case ENTRANCE_TYPE_RIDE_ENTRANCE: - ride_set_entrance_location( - ride, stationIndex, - { loc.x / 32, loc.y / 32, entranceElement->base_height, - static_cast(entranceElement->GetDirection()) }); - break; - case ENTRANCE_TYPE_RIDE_EXIT: - ride_set_exit_location( - ride, stationIndex, - { loc.x / 32, loc.y / 32, entranceElement->base_height, - static_cast(entranceElement->GetDirection()) }); - break; - } - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_wall_set_slope( - const CoordsXY& loc, int32_t elementIndex, int32_t slopeValue, bool isExecuting) -{ - TileElement* const wallElement = map_get_nth_element_at(loc, elementIndex); - - if (wallElement == nullptr || wallElement->GetType() != TILE_ELEMENT_TYPE_WALL) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) - { - // Set new slope value - wallElement->AsWall()->SetSlope(slopeValue); - - map_invalidate_tile_full(loc); - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_wall_animation_frame_offset( - const CoordsXY& loc, int16_t elementIndex, int8_t animationFrameOffset, bool isExecuting) -{ - TileElement* const wallElement = map_get_nth_element_at(loc, elementIndex); - - if (wallElement == nullptr || wallElement->GetType() != TILE_ELEMENT_TYPE_WALL) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) - { - uint8_t animationFrame = wallElement->AsWall()->GetAnimationFrame(); - wallElement->AsWall()->SetAnimationFrame(animationFrame + animationFrameOffset); - - map_invalidate_tile_full(loc); - - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } - } - - return std::make_unique(); -} - -// Changes the height of all track elements that belong to the same track piece -// Broxzier: Copied from track_remove and stripped of unneeded code, but I think this should be smaller -GameActionResultPtr tile_inspector_track_base_height_offset( - const CoordsXY& loc, int32_t elementIndex, int8_t offset, bool isExecuting) -{ - if (offset == 0) return std::make_unique(); + } - TileElement* const trackElement = map_get_nth_element_at(loc, elementIndex); - - if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) + GameActionResultPtr SurfaceShowParkFences(const CoordsXY& loc, bool showFences, bool isExecuting) { - auto type = trackElement->AsTrack()->GetTrackType(); - int16_t originX = loc.x; - int16_t originY = loc.y; - int16_t originZ = trackElement->GetBaseZ(); - uint8_t rotation = trackElement->GetDirection(); - auto rideIndex = trackElement->AsTrack()->GetRideIndex(); - auto ride = get_ride(rideIndex); + auto* const surfaceelement = map_get_surface_element_at(loc); + + // No surface element on tile + if (surfaceelement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) + { + if (!showFences) + surfaceelement->SetParkFences(0); + else + update_park_fences(loc); + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } + } + + return std::make_unique(); + } + + GameActionResultPtr SurfaceToggleCorner(const CoordsXY& loc, int32_t cornerIndex, bool isExecuting) + { + auto* const surfaceElement = map_get_surface_element_at(loc); + + // No surface element on tile + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) + { + const uint8_t originalSlope = surfaceElement->GetSlope(); + const bool diagonal = (originalSlope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) >> 4; + + uint8_t newSlope = surfaceElement->GetSlope() ^ (1 << cornerIndex); + surfaceElement->SetSlope(newSlope); + if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) + { + surfaceElement->clearance_height = surfaceElement->base_height + 2; + } + else + { + surfaceElement->clearance_height = surfaceElement->base_height; + } + + // All corners are raised + if ((surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) == TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) + { + uint8_t slope = TILE_ELEMENT_SLOPE_FLAT; + + if (diagonal) + { + switch (originalSlope & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) + { + case TILE_ELEMENT_SLOPE_S_CORNER_DN: + slope |= TILE_ELEMENT_SLOPE_N_CORNER_UP; + break; + case TILE_ELEMENT_SLOPE_W_CORNER_DN: + slope |= TILE_ELEMENT_SLOPE_E_CORNER_UP; + break; + case TILE_ELEMENT_SLOPE_N_CORNER_DN: + slope |= TILE_ELEMENT_SLOPE_S_CORNER_UP; + break; + case TILE_ELEMENT_SLOPE_E_CORNER_DN: + slope |= TILE_ELEMENT_SLOPE_W_CORNER_UP; + break; + } + } + surfaceElement->SetSlope(slope); + + // Update base and clearance heights + surfaceElement->base_height += 2; + surfaceElement->clearance_height = surfaceElement->base_height + (diagonal ? 2 : 0); + } + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } + } + + return std::make_unique(); + } + + GameActionResultPtr SurfaceToggleDiagonal(const CoordsXY& loc, bool isExecuting) + { + auto* const surfaceElement = map_get_surface_element_at(loc); + + // No surface element on tile + if (surfaceElement == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) + { + uint8_t newSlope = surfaceElement->GetSlope() ^ TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT; + surfaceElement->SetSlope(newSlope); + if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) + { + surfaceElement->clearance_height = surfaceElement->base_height + 4; + } + else if (surfaceElement->GetSlope() & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) + { + surfaceElement->clearance_height = surfaceElement->base_height + 2; + } + else + { + surfaceElement->clearance_height = surfaceElement->base_height; + } + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } + } + + return std::make_unique(); + } + + GameActionResultPtr PathSetSloped(const CoordsXY& loc, int32_t elementIndex, bool sloped, bool isExecuting) + { + TileElement* const pathElement = map_get_nth_element_at(loc, elementIndex); + + if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) + { + pathElement->AsPath()->SetSloped(sloped); + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } + } + + return std::make_unique(); + } + + GameActionResultPtr PathSetBroken(const CoordsXY& loc, int32_t elementIndex, bool broken, bool isExecuting) + { + TileElement* const pathElement = map_get_nth_element_at(loc, elementIndex); + + if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) + { + pathElement->AsPath()->SetIsBroken(broken); + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } + } + + return std::make_unique(); + } + + GameActionResultPtr PathToggleEdge(const CoordsXY& loc, int32_t elementIndex, int32_t edgeIndex, bool isExecuting) + { + TileElement* const pathElement = map_get_nth_element_at(loc, elementIndex); + + if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) + { + uint8_t newEdges = pathElement->AsPath()->GetEdgesAndCorners() ^ (1 << edgeIndex); + pathElement->AsPath()->SetEdgesAndCorners(newEdges); + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } + } + + return std::make_unique(); + } + + GameActionResultPtr EntranceMakeUsable(const CoordsXY& loc, int32_t elementIndex, bool isExecuting) + { + TileElement* const entranceElement = map_get_nth_element_at(loc, elementIndex); + + if (entranceElement == nullptr || entranceElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + auto ride = get_ride(entranceElement->AsEntrance()->GetRideIndex()); if (ride == nullptr) return std::make_unique(GameActions::Status::Unknown, STR_NONE); - auto trackBlock = TrackBlocks[type]; - trackBlock += trackElement->AsTrack()->GetSequenceIndex(); - - uint8_t originDirection = trackElement->GetDirection(); - CoordsXY offsets = { trackBlock->x, trackBlock->y }; - CoordsXY coords = { originX, originY }; - coords += offsets.Rotate(direction_reverse(originDirection)); - - originX = static_cast(coords.x); - originY = static_cast(coords.y); - originZ -= trackBlock->z; - - trackBlock = TrackBlocks[type]; - for (; trackBlock->index != 255; trackBlock++) + if (isExecuting) { - CoordsXY elem = { originX, originY }; - int16_t elemZ = originZ; - offsets.x = trackBlock->x; - offsets.y = trackBlock->y; - elem += offsets.Rotate(originDirection); - elemZ += trackBlock->z; + auto stationIndex = entranceElement->AsEntrance()->GetStationIndex(); - map_invalidate_tile_full(elem); - - bool found = false; - TileElement* tileElement = map_get_first_element_at({ elem.x, elem.y }); - do + switch (entranceElement->AsEntrance()->GetEntranceType()) { - if (tileElement == nullptr) + case ENTRANCE_TYPE_RIDE_ENTRANCE: + ride_set_entrance_location( + ride, stationIndex, + { loc.x / 32, loc.y / 32, entranceElement->base_height, + static_cast(entranceElement->GetDirection()) }); + break; + case ENTRANCE_TYPE_RIDE_EXIT: + ride_set_exit_location( + ride, stationIndex, + { loc.x / 32, loc.y / 32, entranceElement->base_height, + static_cast(entranceElement->GetDirection()) }); break; - - if (tileElement->GetBaseZ() != elemZ) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if (tileElement->GetDirection() != rotation) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) - continue; - - if (tileElement->AsTrack()->GetTrackType() != type) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_error("Track map element part not found!"); - return std::make_unique(GameActions::Status::Unknown, STR_NONE); } - // track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is for when - // you decrease the map size. - openrct2_assert(map_get_surface_element_at(elem) != nullptr, "No surface at %d,%d", elem.x >> 5, elem.y >> 5); - - // Keep? - // invalidate_test_results(ride); - - tileElement->base_height += offset; - tileElement->clearance_height += offset; + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } } + + return std::make_unique(); } - // TODO: Only invalidate when one of the affected tiles is selected - window_invalidate_by_class(WC_TILE_INSPECTOR); - - return std::make_unique(); -} - -// Sets chainlift, optionally for an entire track block -// Broxzier: Basically a copy of the above function, with just two different lines... should probably be combined somehow -GameActionResultPtr tile_inspector_track_set_chain( - const CoordsXY& loc, int32_t elementIndex, bool entireTrackBlock, bool setChain, bool isExecuting) -{ - TileElement* const trackElement = map_get_nth_element_at(loc, elementIndex); - - if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) + GameActionResultPtr WallSetSlope(const CoordsXY& loc, int32_t elementIndex, int32_t slopeValue, bool isExecuting) { - if (!entireTrackBlock) - { - // Set chain for only the selected piece - if (trackElement->AsTrack()->HasChain() != setChain) - { - trackElement->AsTrack()->SetHasChain(setChain); - } + TileElement* const wallElement = map_get_nth_element_at(loc, elementIndex); + if (wallElement == nullptr || wallElement->GetType() != TILE_ELEMENT_TYPE_WALL) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) + { + // Set new slope value + wallElement->AsWall()->SetSlope(slopeValue); + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } + } + + return std::make_unique(); + } + + GameActionResultPtr WallAnimationFrameOffset( + const CoordsXY& loc, int16_t elementIndex, int8_t animationFrameOffset, bool isExecuting) + { + TileElement* const wallElement = map_get_nth_element_at(loc, elementIndex); + + if (wallElement == nullptr || wallElement->GetType() != TILE_ELEMENT_TYPE_WALL) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) + { + uint8_t animationFrame = wallElement->AsWall()->GetAnimationFrame(); + wallElement->AsWall()->SetAnimationFrame(animationFrame + animationFrameOffset); + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } + } + + return std::make_unique(); + } + + // Changes the height of all track elements that belong to the same track piece + // Broxzier: Copied from track_remove and stripped of unneeded code, but I think this should be smaller + GameActionResultPtr TrackBaseHeightOffset(const CoordsXY& loc, int32_t elementIndex, int8_t offset, bool isExecuting) + { + if (offset == 0) return std::make_unique(); - } - auto type = trackElement->AsTrack()->GetTrackType(); - int16_t originX = loc.x; - int16_t originY = loc.y; - int16_t originZ = trackElement->GetBaseZ(); - uint8_t rotation = trackElement->GetDirection(); - auto rideIndex = trackElement->AsTrack()->GetRideIndex(); - auto ride = get_ride(rideIndex); - if (ride == nullptr) + TileElement* const trackElement = map_get_nth_element_at(loc, elementIndex); + + if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) return std::make_unique(GameActions::Status::Unknown, STR_NONE); - auto trackBlock = TrackBlocks[type]; - trackBlock += trackElement->AsTrack()->GetSequenceIndex(); - - uint8_t originDirection = trackElement->GetDirection(); - CoordsXY offsets = { trackBlock->x, trackBlock->y }; - CoordsXY coords = { originX, originY }; - coords += offsets.Rotate(direction_reverse(originDirection)); - - originX = static_cast(coords.x); - originY = static_cast(coords.y); - originZ -= trackBlock->z; - - trackBlock = TrackBlocks[type]; - for (; trackBlock->index != 255; trackBlock++) + if (isExecuting) { - CoordsXY elem = { originX, originY }; - int16_t elemZ = originZ; - offsets.x = trackBlock->x; - offsets.y = trackBlock->y; - elem += offsets.Rotate(originDirection); - elemZ += trackBlock->z; - - map_invalidate_tile_full(elem); - - bool found = false; - TileElement* tileElement = map_get_first_element_at({ elem.x, elem.y }); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != elemZ) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if (tileElement->GetDirection() != rotation) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) - continue; - - if (tileElement->AsTrack()->GetTrackType() != type) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) - { - log_error("Track map element part not found!"); + auto type = trackElement->AsTrack()->GetTrackType(); + int16_t originX = loc.x; + int16_t originY = loc.y; + int16_t originZ = trackElement->GetBaseZ(); + uint8_t rotation = trackElement->GetDirection(); + auto rideIndex = trackElement->AsTrack()->GetRideIndex(); + auto ride = get_ride(rideIndex); + if (ride == nullptr) return std::make_unique(GameActions::Status::Unknown, STR_NONE); - } - // track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is for when - // you decrease the map size. - openrct2_assert(map_get_surface_element_at(elem) != nullptr, "No surface at %d,%d", elem.x >> 5, elem.y >> 5); + auto trackBlock = TrackBlocks[type]; + trackBlock += trackElement->AsTrack()->GetSequenceIndex(); - // Keep? - // invalidate_test_results(ride); + uint8_t originDirection = trackElement->GetDirection(); + CoordsXY offsets = { trackBlock->x, trackBlock->y }; + CoordsXY coords = { originX, originY }; + coords += offsets.Rotate(direction_reverse(originDirection)); - if (tileElement->AsTrack()->HasChain() != setChain) + originX = static_cast(coords.x); + originY = static_cast(coords.y); + originZ -= trackBlock->z; + + trackBlock = TrackBlocks[type]; + for (; trackBlock->index != 255; trackBlock++) { - tileElement->AsTrack()->SetHasChain(setChain); + CoordsXY elem = { originX, originY }; + int16_t elemZ = originZ; + offsets.x = trackBlock->x; + offsets.y = trackBlock->y; + elem += offsets.Rotate(originDirection); + elemZ += trackBlock->z; + + map_invalidate_tile_full(elem); + + bool found = false; + TileElement* tileElement = map_get_first_element_at({ elem.x, elem.y }); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetBaseZ() != elemZ) + continue; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if (tileElement->GetDirection() != rotation) + continue; + + if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) + continue; + + if (tileElement->AsTrack()->GetTrackType() != type) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_error("Track map element part not found!"); + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + } + + // track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is for + // when you decrease the map size. + openrct2_assert(map_get_surface_element_at(elem) != nullptr, "No surface at %d,%d", elem.x >> 5, elem.y >> 5); + + // Keep? + // invalidate_test_results(ride); + + tileElement->base_height += offset; + tileElement->clearance_height += offset; } } + + // TODO: Only invalidate when one of the affected tiles is selected + window_invalidate_by_class(WC_TILE_INSPECTOR); + + return std::make_unique(); } - // TODO: Only invalidate when one of the affected tiles is selected - window_invalidate_by_class(WC_TILE_INSPECTOR); - - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_track_set_block_brake( - const CoordsXY& loc, int32_t elementIndex, bool blockBrake, bool isExecuting) -{ - TileElement* const trackElement = map_get_nth_element_at(loc, elementIndex); - - if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) + // Sets chainlift, optionally for an entire track block + // Broxzier: Basically a copy of the above function, with just two different lines... should probably be combined somehow + GameActionResultPtr TrackSetChain( + const CoordsXY& loc, int32_t elementIndex, bool entireTrackBlock, bool setChain, bool isExecuting) { - trackElement->AsTrack()->SetBlockBrakeClosed(blockBrake); + TileElement* const trackElement = map_get_nth_element_at(loc, elementIndex); - map_invalidate_tile_full(loc); + if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + if (isExecuting) { - tileInspectorWindow->Invalidate(); + if (!entireTrackBlock) + { + // Set chain for only the selected piece + if (trackElement->AsTrack()->HasChain() != setChain) + { + trackElement->AsTrack()->SetHasChain(setChain); + } + + return std::make_unique(); + } + + auto type = trackElement->AsTrack()->GetTrackType(); + int16_t originX = loc.x; + int16_t originY = loc.y; + int16_t originZ = trackElement->GetBaseZ(); + uint8_t rotation = trackElement->GetDirection(); + auto rideIndex = trackElement->AsTrack()->GetRideIndex(); + auto ride = get_ride(rideIndex); + if (ride == nullptr) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + auto trackBlock = TrackBlocks[type]; + trackBlock += trackElement->AsTrack()->GetSequenceIndex(); + + uint8_t originDirection = trackElement->GetDirection(); + CoordsXY offsets = { trackBlock->x, trackBlock->y }; + CoordsXY coords = { originX, originY }; + coords += offsets.Rotate(direction_reverse(originDirection)); + + originX = static_cast(coords.x); + originY = static_cast(coords.y); + originZ -= trackBlock->z; + + trackBlock = TrackBlocks[type]; + for (; trackBlock->index != 255; trackBlock++) + { + CoordsXY elem = { originX, originY }; + int16_t elemZ = originZ; + offsets.x = trackBlock->x; + offsets.y = trackBlock->y; + elem += offsets.Rotate(originDirection); + elemZ += trackBlock->z; + + map_invalidate_tile_full(elem); + + bool found = false; + TileElement* tileElement = map_get_first_element_at({ elem.x, elem.y }); + do + { + if (tileElement == nullptr) + break; + + if (tileElement->GetBaseZ() != elemZ) + continue; + + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + if (tileElement->GetDirection() != rotation) + continue; + + if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) + continue; + + if (tileElement->AsTrack()->GetTrackType() != type) + continue; + + found = true; + break; + } while (!(tileElement++)->IsLastForTile()); + + if (!found) + { + log_error("Track map element part not found!"); + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + } + + // track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is for + // when you decrease the map size. + openrct2_assert(map_get_surface_element_at(elem) != nullptr, "No surface at %d,%d", elem.x >> 5, elem.y >> 5); + + // Keep? + // invalidate_test_results(ride); + + if (tileElement->AsTrack()->HasChain() != setChain) + { + tileElement->AsTrack()->SetHasChain(setChain); + } + } } + + // TODO: Only invalidate when one of the affected tiles is selected + window_invalidate_by_class(WC_TILE_INSPECTOR); + + return std::make_unique(); } - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_track_set_indestructible( - const CoordsXY& loc, int32_t elementIndex, bool isIndestructible, bool isExecuting) -{ - TileElement* const trackElement = map_get_nth_element_at(loc, elementIndex); - - if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) + GameActionResultPtr TrackSetBlockBrake(const CoordsXY& loc, int32_t elementIndex, bool blockBrake, bool isExecuting) { - trackElement->AsTrack()->SetIsIndestructible(isIndestructible); + TileElement* const trackElement = map_get_nth_element_at(loc, elementIndex); - map_invalidate_tile_full(loc); + if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + if (isExecuting) { - tileInspectorWindow->Invalidate(); + trackElement->AsTrack()->SetBlockBrakeClosed(blockBrake); + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } } + + return std::make_unique(); } - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_scenery_set_quarter_location( - const CoordsXY& loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting) -{ - TileElement* const tileElement = map_get_nth_element_at(loc, elementIndex); - - if (tileElement == nullptr || tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) + GameActionResultPtr TrackSetIndestructible( + const CoordsXY& loc, int32_t elementIndex, bool isIndestructible, bool isExecuting) { - // Set quadrant index - tileElement->AsSmallScenery()->SetSceneryQuadrant(quarterIndex); + TileElement* const trackElement = map_get_nth_element_at(loc, elementIndex); - // Update collision - tileElement->SetOccupiedQuadrants(1 << ((quarterIndex + 2) & 3)); + if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); - map_invalidate_tile_full(loc); - if (loc == windowTileInspectorTile.ToCoordsXY()) + if (isExecuting) { - window_invalidate_by_class(WC_TILE_INSPECTOR); + trackElement->AsTrack()->SetIsIndestructible(isIndestructible); + + map_invalidate_tile_full(loc); + + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } } + + return std::make_unique(); } - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_scenery_set_quarter_collision( - const CoordsXY& loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting) -{ - TileElement* const tileElement = map_get_nth_element_at(loc, elementIndex); - - if (tileElement == nullptr || tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) + GameActionResultPtr ScenerySetQuarterLocation( + const CoordsXY& loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting) { - auto occupiedQuadrants = tileElement->GetOccupiedQuadrants(); - occupiedQuadrants ^= 1 << quarterIndex; - tileElement->SetOccupiedQuadrants(occupiedQuadrants); + TileElement* const tileElement = map_get_nth_element_at(loc, elementIndex); - map_invalidate_tile_full(loc); - if (loc == windowTileInspectorTile.ToCoordsXY()) + if (tileElement == nullptr || tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) { - window_invalidate_by_class(WC_TILE_INSPECTOR); + // Set quadrant index + tileElement->AsSmallScenery()->SetSceneryQuadrant(quarterIndex); + + // Update collision + tileElement->SetOccupiedQuadrants(1 << ((quarterIndex + 2) & 3)); + + map_invalidate_tile_full(loc); + if (loc == windowTileInspectorTile.ToCoordsXY()) + { + window_invalidate_by_class(WC_TILE_INSPECTOR); + } } + + return std::make_unique(); } - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_banner_toggle_blocking_edge( - const CoordsXY& loc, int32_t elementIndex, int32_t edgeIndex, bool isExecuting) -{ - TileElement* const bannerElement = map_get_nth_element_at(loc, elementIndex); - - if (bannerElement == nullptr || bannerElement->GetType() != TILE_ELEMENT_TYPE_BANNER) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) + GameActionResultPtr ScenerySetQuarterCollision( + const CoordsXY& loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting) { - uint8_t edges = bannerElement->AsBanner()->GetAllowedEdges(); - edges ^= (1 << edgeIndex); - bannerElement->AsBanner()->SetAllowedEdges(edges); + TileElement* const tileElement = map_get_nth_element_at(loc, elementIndex); - if (loc == windowTileInspectorTile.ToCoordsXY()) + if (tileElement == nullptr || tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) { - window_invalidate_by_class(WC_TILE_INSPECTOR); + auto occupiedQuadrants = tileElement->GetOccupiedQuadrants(); + occupiedQuadrants ^= 1 << quarterIndex; + tileElement->SetOccupiedQuadrants(occupiedQuadrants); + + map_invalidate_tile_full(loc); + if (loc == windowTileInspectorTile.ToCoordsXY()) + { + window_invalidate_by_class(WC_TILE_INSPECTOR); + } } + + return std::make_unique(); } - return std::make_unique(); -} - -GameActionResultPtr tile_inspector_corrupt_clamp(const CoordsXY& loc, int32_t elementIndex, bool isExecuting) -{ - TileElement* const corruptElement = map_get_nth_element_at(loc, elementIndex); - - if (corruptElement == nullptr || corruptElement->GetType() != TILE_ELEMENT_TYPE_CORRUPT) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (corruptElement->IsLastForTile()) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); - - if (isExecuting) + GameActionResultPtr BannerToggleBlockingEdge(const CoordsXY& loc, int32_t elementIndex, int32_t edgeIndex, bool isExecuting) { - TileElement* const nextElement = corruptElement + 1; - corruptElement->base_height = corruptElement->clearance_height = nextElement->base_height; + TileElement* const bannerElement = map_get_nth_element_at(loc, elementIndex); - if (loc == windowTileInspectorTile.ToCoordsXY()) + if (bannerElement == nullptr || bannerElement->GetType() != TILE_ELEMENT_TYPE_BANNER) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) { - window_invalidate_by_class(WC_TILE_INSPECTOR); + uint8_t edges = bannerElement->AsBanner()->GetAllowedEdges(); + edges ^= (1 << edgeIndex); + bannerElement->AsBanner()->SetAllowedEdges(edges); + + if (loc == windowTileInspectorTile.ToCoordsXY()) + { + window_invalidate_by_class(WC_TILE_INSPECTOR); + } } + + return std::make_unique(); } - return std::make_unique(); -} + GameActionResultPtr CorruptClamp(const CoordsXY& loc, int32_t elementIndex, bool isExecuting) + { + TileElement* const corruptElement = map_get_nth_element_at(loc, elementIndex); + + if (corruptElement == nullptr || corruptElement->GetType() != TILE_ELEMENT_TYPE_CORRUPT) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (corruptElement->IsLastForTile()) + return std::make_unique(GameActions::Status::Unknown, STR_NONE); + + if (isExecuting) + { + TileElement* const nextElement = corruptElement + 1; + corruptElement->base_height = corruptElement->clearance_height = nextElement->base_height; + + if (loc == windowTileInspectorTile.ToCoordsXY()) + { + window_invalidate_by_class(WC_TILE_INSPECTOR); + } + } + + return std::make_unique(); + } + +} // namespace OpenRCT2::TileInspector diff --git a/src/openrct2/world/TileInspector.h b/src/openrct2/world/TileInspector.h index e68fa02e0e..1c1d9d180e 100644 --- a/src/openrct2/world/TileInspector.h +++ b/src/openrct2/world/TileInspector.h @@ -17,39 +17,39 @@ namespace GameActions class Result; } -using GameActionResultPtr = std::unique_ptr; -GameActionResultPtr tile_inspector_insert_corrupt_at(const CoordsXY& loc, int16_t elementIndex, bool isExecuting); -GameActionResultPtr tile_inspector_remove_element_at(const CoordsXY& loc, int16_t elementIndex, bool isExecuting); -GameActionResultPtr tile_inspector_swap_elements_at(const CoordsXY& loc, int16_t first, int16_t second, bool isExecuting); -GameActionResultPtr tile_inspector_rotate_element_at(const CoordsXY& loc, int32_t elementIndex, bool isExecuting); -GameActionResultPtr tile_inspector_paste_element_at(const CoordsXY& loc, TileElement element, bool isExecuting); -GameActionResultPtr tile_inspector_sort_elements_at(const CoordsXY& loc, bool isExecuting); -GameActionResultPtr tile_inspector_any_base_height_offset( - const CoordsXY& loc, int16_t elementIndex, int8_t heightOffset, bool isExecuting); -GameActionResultPtr tile_inspector_surface_show_park_fences(const CoordsXY& loc, bool enabled, bool isExecuting); -GameActionResultPtr tile_inspector_surface_toggle_corner(const CoordsXY& loc, int32_t cornerIndex, bool isExecuting); -GameActionResultPtr tile_inspector_surface_toggle_diagonal(const CoordsXY& loc, bool isExecuting); -GameActionResultPtr tile_inspector_path_set_sloped(const CoordsXY& loc, int32_t elementIndex, bool sloped, bool isExecuting); -GameActionResultPtr tile_inspector_path_set_broken(const CoordsXY& loc, int32_t elementIndex, bool broken, bool isExecuting); -GameActionResultPtr tile_inspector_path_toggle_edge( - const CoordsXY& loc, int32_t elementIndex, int32_t cornerIndex, bool isExecuting); -GameActionResultPtr tile_inspector_entrance_make_usable(const CoordsXY& loc, int32_t elementIndex, bool isExecuting); -GameActionResultPtr tile_inspector_wall_set_slope( - const CoordsXY& loc, int32_t elementIndex, int32_t slopeValue, bool isExecuting); -GameActionResultPtr tile_inspector_wall_animation_frame_offset( - const CoordsXY& loc, int16_t elementIndex, int8_t animationFrameOffset, bool isExecuting); -GameActionResultPtr tile_inspector_track_base_height_offset( - const CoordsXY& loc, int32_t elementIndex, int8_t offset, bool isExecuting); -GameActionResultPtr tile_inspector_track_set_block_brake( - const CoordsXY& loc, int32_t elementIndex, bool blockBrake, bool isExecuting); -GameActionResultPtr tile_inspector_track_set_indestructible( - const CoordsXY& loc, int32_t elementIndex, bool isIndestructible, bool isExecuting); -GameActionResultPtr tile_inspector_track_set_chain( - const CoordsXY& loc, int32_t elementIndex, bool entireTrackBlock, bool setChain, bool isExecuting); -GameActionResultPtr tile_inspector_scenery_set_quarter_location( - const CoordsXY& loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting); -GameActionResultPtr tile_inspector_scenery_set_quarter_collision( - const CoordsXY& loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting); -GameActionResultPtr tile_inspector_banner_toggle_blocking_edge( - const CoordsXY& loc, int32_t elementIndex, int32_t edgeIndex, bool isExecuting); -GameActionResultPtr tile_inspector_corrupt_clamp(const CoordsXY& loc, int32_t elementIndex, bool isExecuting); +namespace OpenRCT2::TileInspector +{ + using GameActionResultPtr = std::unique_ptr; + + GameActionResultPtr InsertCorruptElementAt(const CoordsXY& loc, int16_t elementIndex, bool isExecuting); + GameActionResultPtr RemoveElementAt(const CoordsXY& loc, int16_t elementIndex, bool isExecuting); + GameActionResultPtr SwapElementsAt(const CoordsXY& loc, int16_t first, int16_t second, bool isExecuting); + GameActionResultPtr RotateElementAt(const CoordsXY& loc, int32_t elementIndex, bool isExecuting); + GameActionResultPtr PasteElementAt(const CoordsXY& loc, TileElement element, bool isExecuting); + GameActionResultPtr SortElementsAt(const CoordsXY& loc, bool isExecuting); + GameActionResultPtr AnyBaseHeightOffset(const CoordsXY& loc, int16_t elementIndex, int8_t heightOffset, bool isExecuting); + GameActionResultPtr SurfaceShowParkFences(const CoordsXY& loc, bool enabled, bool isExecuting); + GameActionResultPtr SurfaceToggleCorner(const CoordsXY& loc, int32_t cornerIndex, bool isExecuting); + GameActionResultPtr SurfaceToggleDiagonal(const CoordsXY& loc, bool isExecuting); + GameActionResultPtr PathSetSloped(const CoordsXY& loc, int32_t elementIndex, bool sloped, bool isExecuting); + GameActionResultPtr PathSetBroken(const CoordsXY& loc, int32_t elementIndex, bool broken, bool isExecuting); + GameActionResultPtr PathToggleEdge(const CoordsXY& loc, int32_t elementIndex, int32_t cornerIndex, bool isExecuting); + GameActionResultPtr EntranceMakeUsable(const CoordsXY& loc, int32_t elementIndex, bool isExecuting); + GameActionResultPtr WallSetSlope(const CoordsXY& loc, int32_t elementIndex, int32_t slopeValue, bool isExecuting); + GameActionResultPtr WallAnimationFrameOffset( + const CoordsXY& loc, int16_t elementIndex, int8_t animationFrameOffset, bool isExecuting); + GameActionResultPtr TrackBaseHeightOffset(const CoordsXY& loc, int32_t elementIndex, int8_t offset, bool isExecuting); + GameActionResultPtr TrackSetBlockBrake(const CoordsXY& loc, int32_t elementIndex, bool blockBrake, bool isExecuting); + GameActionResultPtr TrackSetIndestructible( + const CoordsXY& loc, int32_t elementIndex, bool isIndestructible, bool isExecuting); + GameActionResultPtr TrackSetChain( + const CoordsXY& loc, int32_t elementIndex, bool entireTrackBlock, bool setChain, bool isExecuting); + GameActionResultPtr ScenerySetQuarterLocation( + const CoordsXY& loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting); + GameActionResultPtr ScenerySetQuarterCollision( + const CoordsXY& loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting); + GameActionResultPtr BannerToggleBlockingEdge( + const CoordsXY& loc, int32_t elementIndex, int32_t edgeIndex, bool isExecuting); + GameActionResultPtr CorruptClamp(const CoordsXY& loc, int32_t elementIndex, bool isExecuting); + +} // namespace OpenRCT2::TileInspector From c1767bc98bb3cc45fd1ba3571b785ff8cbb2f535 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 19 Feb 2021 18:17:04 +0200 Subject: [PATCH 2/6] Rename function and use std::swap --- src/openrct2/world/TileInspector.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index d5d7cb41a8..0b7679aa32 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -30,13 +30,15 @@ #include "Scenery.h" #include "Surface.h" +#include + TileCoordsXY windowTileInspectorTile; int32_t windowTileInspectorElementCount = 0; int32_t windowTileInspectorSelectedIndex; namespace OpenRCT2::TileInspector { - static bool map_swap_elements_at(const CoordsXY& loc, int16_t first, int16_t second) + static bool SwapTileElements(const CoordsXY& loc, int16_t first, int16_t second) { TileElement* const firstElement = map_get_nth_element_at(loc, first); TileElement* const secondElement = map_get_nth_element_at(loc, second); @@ -58,9 +60,7 @@ namespace OpenRCT2::TileInspector } // Swap their memory - TileElement temp = *firstElement; - *firstElement = *secondElement; - *secondElement = temp; + std::swap(*firstElement, *secondElement); // Swap the 'last map element for tile' flag if either one of them was last if ((firstElement)->IsLastForTile() || (secondElement)->IsLastForTile()) @@ -109,7 +109,7 @@ namespace OpenRCT2::TileInspector // this way it's placed under the selected element, even when there are multiple elements with the same base height for (int16_t i = 0; i < elementIndex; i++) { - if (!map_swap_elements_at(loc, i, i + 1)) + if (!SwapTileElements(loc, i, i + 1)) { // don't return error here, we've already inserted an element // and moved it as far as we could, the only sensible thing left @@ -246,7 +246,7 @@ namespace OpenRCT2::TileInspector { if (isExecuting) { - if (!map_swap_elements_at(loc, first, second)) + if (!SwapTileElements(loc, first, second)) { return std::make_unique(GameActions::Status::Unknown, STR_NONE); } @@ -441,7 +441,7 @@ namespace OpenRCT2::TileInspector || (otherElement->base_height == currentElement->base_height && otherElement->clearance_height > currentElement->clearance_height))) { - if (!map_swap_elements_at(loc, currentId - 1, currentId)) + if (!SwapTileElements(loc, currentId - 1, currentId)) { // don't return error here, we've already ran some actions // and moved things as far as we could, the only sensible From ffc2e7a0e7fca3ab8292bb4efe20b8c5331584e4 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 19 Feb 2021 18:28:09 +0200 Subject: [PATCH 3/6] Cleanup duplicate code --- src/openrct2/world/TileInspector.cpp | 218 +++++++++------------------ 1 file changed, 72 insertions(+), 146 deletions(-) diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index 0b7679aa32..08b73ecd8e 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -31,6 +31,7 @@ #include "Surface.h" #include +#include TileCoordsXY windowTileInspectorTile; int32_t windowTileInspectorElementCount = 0; @@ -72,6 +73,16 @@ namespace OpenRCT2::TileInspector return true; } + static void InvalidateTileInspector(const CoordsXY& loc) + { + // Update the tile inspector's list for everyone who has the tile selected + rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + { + tileInspectorWindow->Invalidate(); + } + } + /** * Inserts a corrupt element under a given element on a given tile * @param x The x coordinate of the tile @@ -120,20 +131,13 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - // Update the tile inspector's list for everyone who has the tile selected - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + windowTileInspectorElementCount++; + if (windowTileInspectorSelectedIndex > elementIndex) { - windowTileInspectorElementCount++; - - // Keep other elements (that are not being hidden) selected - if (windowTileInspectorSelectedIndex > elementIndex) - { - windowTileInspectorSelectedIndex++; - } - - tileInspectorWindow->Invalidate(); + windowTileInspectorSelectedIndex++; } + + InvalidateTileInspector(loc); } // Nothing went wrong @@ -221,22 +225,18 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); // Update the window - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + windowTileInspectorElementCount--; + + if (windowTileInspectorSelectedIndex > elementIndex) { - windowTileInspectorElementCount--; - - if (windowTileInspectorSelectedIndex > elementIndex) - { - windowTileInspectorSelectedIndex--; - } - else if (windowTileInspectorSelectedIndex == elementIndex) - { - windowTileInspectorSelectedIndex = -1; - } - - tileInspectorWindow->Invalidate(); + windowTileInspectorSelectedIndex--; } + else if (windowTileInspectorSelectedIndex == elementIndex) + { + windowTileInspectorSelectedIndex = -1; + } + + InvalidateTileInspector(loc); } return std::make_unique(); @@ -252,18 +252,13 @@ namespace OpenRCT2::TileInspector } map_invalidate_tile_full(loc); - // Update the window - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - // If one of them was selected, update selected list item - if (windowTileInspectorSelectedIndex == first) - windowTileInspectorSelectedIndex = second; - else if (windowTileInspectorSelectedIndex == second) - windowTileInspectorSelectedIndex = first; + // If one of them was selected, update selected list item + if (windowTileInspectorSelectedIndex == first) + windowTileInspectorSelectedIndex = second; + else if (windowTileInspectorSelectedIndex == second) + windowTileInspectorSelectedIndex = first; - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -342,10 +337,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - if (loc == windowTileInspectorTile.ToCoordsXY()) - { - window_invalidate_by_class(WC_TILE_INSPECTOR); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -392,20 +384,16 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && tileLoc == windowTileInspectorTile) - { - windowTileInspectorElementCount++; + windowTileInspectorElementCount++; - // Select new element if there was none selected already - int16_t newIndex = static_cast((pastedElement - map_get_first_element_at(loc))); - if (windowTileInspectorSelectedIndex == -1) - windowTileInspectorSelectedIndex = newIndex; - else if (windowTileInspectorSelectedIndex >= newIndex) - windowTileInspectorSelectedIndex++; + // Select new element if there was none selected already + int16_t newIndex = static_cast((pastedElement - map_get_first_element_at(loc))); + if (windowTileInspectorSelectedIndex == -1) + windowTileInspectorSelectedIndex = newIndex; + else if (windowTileInspectorSelectedIndex >= newIndex) + windowTileInspectorSelectedIndex++; - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -458,12 +446,9 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); // Deselect tile for clients who had it selected - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - windowTileInspectorSelectedIndex = -1; - tileInspectorWindow->Invalidate(); - } + windowTileInspectorSelectedIndex = -1; + + InvalidateTileInspector(loc); } return std::make_unique(); @@ -536,11 +521,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -563,11 +544,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -629,11 +606,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -666,11 +639,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -689,11 +658,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -712,11 +677,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -736,11 +697,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -777,11 +734,7 @@ namespace OpenRCT2::TileInspector break; } - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -801,11 +754,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -826,11 +775,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -916,8 +861,8 @@ namespace OpenRCT2::TileInspector return std::make_unique(GameActions::Status::Unknown, STR_NONE); } - // track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is for - // when you decrease the map size. + // track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is + // for when you decrease the map size. openrct2_assert(map_get_surface_element_at(elem) != nullptr, "No surface at %d,%d", elem.x >> 5, elem.y >> 5); // Keep? @@ -926,16 +871,16 @@ namespace OpenRCT2::TileInspector tileElement->base_height += offset; tileElement->clearance_height += offset; } - } - // TODO: Only invalidate when one of the affected tiles is selected - window_invalidate_by_class(WC_TILE_INSPECTOR); + InvalidateTileInspector(loc); + } return std::make_unique(); } // Sets chainlift, optionally for an entire track block - // Broxzier: Basically a copy of the above function, with just two different lines... should probably be combined somehow + // Broxzier: Basically a copy of the above function, with just two different lines... should probably be combined + // somehow GameActionResultPtr TrackSetChain( const CoordsXY& loc, int32_t elementIndex, bool entireTrackBlock, bool setChain, bool isExecuting) { @@ -1023,8 +968,8 @@ namespace OpenRCT2::TileInspector return std::make_unique(GameActions::Status::Unknown, STR_NONE); } - // track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is for - // when you decrease the map size. + // track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is + // for when you decrease the map size. openrct2_assert(map_get_surface_element_at(elem) != nullptr, "No surface at %d,%d", elem.x >> 5, elem.y >> 5); // Keep? @@ -1035,10 +980,9 @@ namespace OpenRCT2::TileInspector tileElement->AsTrack()->SetHasChain(setChain); } } - } - // TODO: Only invalidate when one of the affected tiles is selected - window_invalidate_by_class(WC_TILE_INSPECTOR); + InvalidateTileInspector(loc); + } return std::make_unique(); } @@ -1056,11 +1000,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -1080,11 +1020,7 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) - { - tileInspectorWindow->Invalidate(); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -1107,10 +1043,8 @@ namespace OpenRCT2::TileInspector tileElement->SetOccupiedQuadrants(1 << ((quarterIndex + 2) & 3)); map_invalidate_tile_full(loc); - if (loc == windowTileInspectorTile.ToCoordsXY()) - { - window_invalidate_by_class(WC_TILE_INSPECTOR); - } + + InvalidateTileInspector(loc); } return std::make_unique(); @@ -1131,10 +1065,8 @@ namespace OpenRCT2::TileInspector tileElement->SetOccupiedQuadrants(occupiedQuadrants); map_invalidate_tile_full(loc); - if (loc == windowTileInspectorTile.ToCoordsXY()) - { - window_invalidate_by_class(WC_TILE_INSPECTOR); - } + + InvalidateTileInspector(loc); } return std::make_unique(); @@ -1153,10 +1085,7 @@ namespace OpenRCT2::TileInspector edges ^= (1 << edgeIndex); bannerElement->AsBanner()->SetAllowedEdges(edges); - if (loc == windowTileInspectorTile.ToCoordsXY()) - { - window_invalidate_by_class(WC_TILE_INSPECTOR); - } + InvalidateTileInspector(loc); } return std::make_unique(); @@ -1177,10 +1106,7 @@ namespace OpenRCT2::TileInspector TileElement* const nextElement = corruptElement + 1; corruptElement->base_height = corruptElement->clearance_height = nextElement->base_height; - if (loc == windowTileInspectorTile.ToCoordsXY()) - { - window_invalidate_by_class(WC_TILE_INSPECTOR); - } + InvalidateTileInspector(loc); } return std::make_unique(); From b6138357569013bd2d997e1508a1f8ed7d674cf8 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 19 Feb 2021 18:39:08 +0200 Subject: [PATCH 4/6] Remove more duplicate code --- src/openrct2/world/TileInspector.cpp | 74 ++++------------------------ 1 file changed, 10 insertions(+), 64 deletions(-) diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index 08b73ecd8e..5d92db1514 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -820,42 +820,13 @@ namespace OpenRCT2::TileInspector trackBlock = TrackBlocks[type]; for (; trackBlock->index != 255; trackBlock++) { - CoordsXY elem = { originX, originY }; - int16_t elemZ = originZ; + CoordsXYZD elem = { originX, originY, originZ + trackBlock->z, rotation }; offsets.x = trackBlock->x; offsets.y = trackBlock->y; elem += offsets.Rotate(originDirection); - elemZ += trackBlock->z; - map_invalidate_tile_full(elem); - - bool found = false; - TileElement* tileElement = map_get_first_element_at({ elem.x, elem.y }); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != elemZ) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if (tileElement->GetDirection() != rotation) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) - continue; - - if (tileElement->AsTrack()->GetTrackType() != type) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) + TrackElement* tileElement = map_get_track_element_at_of_type_seq(elem, type, trackBlock->index); + if (tileElement == nullptr) { log_error("Track map element part not found!"); return std::make_unique(GameActions::Status::Unknown, STR_NONE); @@ -865,6 +836,8 @@ namespace OpenRCT2::TileInspector // for when you decrease the map size. openrct2_assert(map_get_surface_element_at(elem) != nullptr, "No surface at %d,%d", elem.x >> 5, elem.y >> 5); + map_invalidate_tile_full(elem); + // Keep? // invalidate_test_results(ride); @@ -927,42 +900,13 @@ namespace OpenRCT2::TileInspector trackBlock = TrackBlocks[type]; for (; trackBlock->index != 255; trackBlock++) { - CoordsXY elem = { originX, originY }; - int16_t elemZ = originZ; + CoordsXYZD elem = { originX, originY, originZ + trackBlock->z, rotation }; offsets.x = trackBlock->x; offsets.y = trackBlock->y; elem += offsets.Rotate(originDirection); - elemZ += trackBlock->z; - map_invalidate_tile_full(elem); - - bool found = false; - TileElement* tileElement = map_get_first_element_at({ elem.x, elem.y }); - do - { - if (tileElement == nullptr) - break; - - if (tileElement->GetBaseZ() != elemZ) - continue; - - if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - - if (tileElement->GetDirection() != rotation) - continue; - - if (tileElement->AsTrack()->GetSequenceIndex() != trackBlock->index) - continue; - - if (tileElement->AsTrack()->GetTrackType() != type) - continue; - - found = true; - break; - } while (!(tileElement++)->IsLastForTile()); - - if (!found) + TrackElement* tileElement = map_get_track_element_at_of_type_seq(elem, type, trackBlock->index); + if (tileElement == nullptr) { log_error("Track map element part not found!"); return std::make_unique(GameActions::Status::Unknown, STR_NONE); @@ -972,6 +916,8 @@ namespace OpenRCT2::TileInspector // for when you decrease the map size. openrct2_assert(map_get_surface_element_at(elem) != nullptr, "No surface at %d,%d", elem.x >> 5, elem.y >> 5); + map_invalidate_tile_full(elem); + // Keep? // invalidate_test_results(ride); From b080bfe1d4d08898007ad41567d1130a8105b95c Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 21 Feb 2021 14:38:15 +0200 Subject: [PATCH 5/6] Only affect the tile inspector state if the position matches --- src/openrct2/world/TileInspector.cpp | 184 +++++++++++++++++++-------- 1 file changed, 128 insertions(+), 56 deletions(-) diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index 5d92db1514..c9dd180a03 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -73,14 +73,15 @@ namespace OpenRCT2::TileInspector return true; } - static void InvalidateTileInspector(const CoordsXY& loc) + static rct_window* GetTileInspectorWithPos(const CoordsXY& loc) { // Update the tile inspector's list for everyone who has the tile selected - rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) + auto* window = window_find_by_class(WC_TILE_INSPECTOR); + if (window != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { - tileInspectorWindow->Invalidate(); + return window; } + return nullptr; } /** @@ -131,13 +132,15 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - windowTileInspectorElementCount++; - if (windowTileInspectorSelectedIndex > elementIndex) + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) { - windowTileInspectorSelectedIndex++; + windowTileInspectorElementCount++; + if (windowTileInspectorSelectedIndex > elementIndex) + { + windowTileInspectorSelectedIndex++; + } + inspector->Invalidate(); } - - InvalidateTileInspector(loc); } // Nothing went wrong @@ -224,19 +227,22 @@ namespace OpenRCT2::TileInspector tile_element_remove(tileElement); map_invalidate_tile_full(loc); - // Update the window - windowTileInspectorElementCount--; - - if (windowTileInspectorSelectedIndex > elementIndex) + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) { - windowTileInspectorSelectedIndex--; - } - else if (windowTileInspectorSelectedIndex == elementIndex) - { - windowTileInspectorSelectedIndex = -1; - } + // Update the window + windowTileInspectorElementCount--; - InvalidateTileInspector(loc); + if (windowTileInspectorSelectedIndex > elementIndex) + { + windowTileInspectorSelectedIndex--; + } + else if (windowTileInspectorSelectedIndex == elementIndex) + { + windowTileInspectorSelectedIndex = -1; + } + + inspector->Invalidate(); + } } return std::make_unique(); @@ -252,13 +258,16 @@ namespace OpenRCT2::TileInspector } map_invalidate_tile_full(loc); - // If one of them was selected, update selected list item - if (windowTileInspectorSelectedIndex == first) - windowTileInspectorSelectedIndex = second; - else if (windowTileInspectorSelectedIndex == second) - windowTileInspectorSelectedIndex = first; + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + // If one of them was selected, update selected list item + if (windowTileInspectorSelectedIndex == first) + windowTileInspectorSelectedIndex = second; + else if (windowTileInspectorSelectedIndex == second) + windowTileInspectorSelectedIndex = first; - InvalidateTileInspector(loc); + inspector->Invalidate(); + } } return std::make_unique(); @@ -337,7 +346,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -384,16 +396,19 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - windowTileInspectorElementCount++; + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + windowTileInspectorElementCount++; - // Select new element if there was none selected already - int16_t newIndex = static_cast((pastedElement - map_get_first_element_at(loc))); - if (windowTileInspectorSelectedIndex == -1) - windowTileInspectorSelectedIndex = newIndex; - else if (windowTileInspectorSelectedIndex >= newIndex) - windowTileInspectorSelectedIndex++; + // Select new element if there was none selected already + int16_t newIndex = static_cast((pastedElement - map_get_first_element_at(loc))); + if (windowTileInspectorSelectedIndex == -1) + windowTileInspectorSelectedIndex = newIndex; + else if (windowTileInspectorSelectedIndex >= newIndex) + windowTileInspectorSelectedIndex++; - InvalidateTileInspector(loc); + inspector->Invalidate(); + } } return std::make_unique(); @@ -445,10 +460,13 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - // Deselect tile for clients who had it selected - windowTileInspectorSelectedIndex = -1; + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + // Deselect tile for clients who had it selected + windowTileInspectorSelectedIndex = -1; - InvalidateTileInspector(loc); + inspector->Invalidate(); + } } return std::make_unique(); @@ -521,7 +539,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -544,7 +565,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -606,7 +630,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -639,7 +666,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -658,7 +688,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -677,7 +710,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -697,7 +733,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -734,7 +773,10 @@ namespace OpenRCT2::TileInspector break; } - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -754,7 +796,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -775,7 +820,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -845,7 +893,10 @@ namespace OpenRCT2::TileInspector tileElement->clearance_height += offset; } - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -927,7 +978,10 @@ namespace OpenRCT2::TileInspector } } - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -946,7 +1000,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -966,7 +1023,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -990,7 +1050,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -1012,7 +1075,10 @@ namespace OpenRCT2::TileInspector map_invalidate_tile_full(loc); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -1031,7 +1097,10 @@ namespace OpenRCT2::TileInspector edges ^= (1 << edgeIndex); bannerElement->AsBanner()->SetAllowedEdges(edges); - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); @@ -1052,7 +1121,10 @@ namespace OpenRCT2::TileInspector TileElement* const nextElement = corruptElement + 1; corruptElement->base_height = corruptElement->clearance_height = nextElement->base_height; - InvalidateTileInspector(loc); + if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) + { + inspector->Invalidate(); + } } return std::make_unique(); From dabeb036a636a93d60a00255532384a1ac3d572c Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 21 Feb 2021 19:13:58 +0200 Subject: [PATCH 6/6] Apply review suggestions --- src/openrct2/world/TileInspector.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index c9dd180a03..1aa8423a71 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -75,7 +75,7 @@ namespace OpenRCT2::TileInspector static rct_window* GetTileInspectorWithPos(const CoordsXY& loc) { - // Update the tile inspector's list for everyone who has the tile selected + // Return the tile inspector window for everyone who has the tile selected auto* window = window_find_by_class(WC_TILE_INSPECTOR); if (window != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { @@ -150,13 +150,14 @@ namespace OpenRCT2::TileInspector static int32_t numLargeScenerySequences(const CoordsXY& loc, const LargeSceneryElement* const largeScenery) { const rct_scenery_entry* const largeEntry = largeScenery->GetEntry(); - const auto* const tiles = largeEntry->large_scenery.tiles; const auto direction = largeScenery->GetDirection(); - - const auto rotatedFirstTile = CoordsXYZ{ CoordsXY{ tiles[largeScenery->GetSequenceIndex()].x_offset, - tiles[largeScenery->GetSequenceIndex()].y_offset } - .Rotate(direction), - tiles[largeScenery->GetSequenceIndex()].z_offset }; + const auto sequenceIndex = largeScenery->GetSequenceIndex(); + const auto* tiles = largeEntry->large_scenery.tiles; + const auto& tile = tiles[sequenceIndex]; + const auto rotatedFirstTile = CoordsXYZ{ + CoordsXY{ tile.x_offset, tile.y_offset }.Rotate(direction), + tile.z_offset, + }; const auto firstTile = CoordsXYZ{ loc, largeScenery->GetBaseZ() } - rotatedFirstTile; auto numFoundElements = 0;