diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 6a73a1ada2..8e8dd3610f 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3642,6 +3642,9 @@ STR_6383 :Open download page STR_6384 :Snow STR_6385 :Heavy Snow STR_6386 :Blizzard +STR_6387 :Can't lower element here... +STR_6388 :Can't raise element here... +STR_6389 :No clearance ############# # Scenarios # diff --git a/distribution/changelog.txt b/distribution/changelog.txt index cd824b0c94..f6c0878a0f 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -3,6 +3,7 @@ - Feature: [#12999] .sea (RCT Classic) scenarios are now listed in the “New Scenario” dialog. - Feature: [#13000] objective_options command for console. - Fix: [#3200] Close Construction window upon selecting vehicle page. +- Fix: [#5904] Empty errors on tile inspector base height change. - Fix: [#8015] RCT2 files are not found when put into the OpenRCT2 folder. - Fix: [#8957] Error title missing when building with insufficient funds - Fix: [#13021] Mowed grass and weeds don't show up in extra zoom levels. diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index 68d79cca3e..eb5700a0d9 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -965,22 +965,22 @@ static void window_tile_inspector_mousedown(rct_window* w, rct_widgetindex widge switch (widgetIndex) { case WIDX_SPINNER_X_INCREASE: - windowTileInspectorTileX = std::min(windowTileInspectorTileX + 1, MAXIMUM_MAP_SIZE_TECHNICAL - 1); + windowTileInspectorTile.x = std::min(windowTileInspectorTile.x + 1, MAXIMUM_MAP_SIZE_TECHNICAL - 1); windowTileInspectorToolMap.x = std::min(windowTileInspectorToolMap.x + 32, MAXIMUM_TILE_START_XY); window_tile_inspector_load_tile(w, nullptr); break; case WIDX_SPINNER_X_DECREASE: - windowTileInspectorTileX = std::max(windowTileInspectorTileX - 1, 0); + windowTileInspectorTile.x = std::max(windowTileInspectorTile.x - 1, 0); windowTileInspectorToolMap.x = std::max(windowTileInspectorToolMap.x - 32, 0); window_tile_inspector_load_tile(w, nullptr); break; case WIDX_SPINNER_Y_INCREASE: - windowTileInspectorTileY = std::min(windowTileInspectorTileY + 1, MAXIMUM_MAP_SIZE_TECHNICAL - 1); + windowTileInspectorTile.y = std::min(windowTileInspectorTile.y + 1, MAXIMUM_MAP_SIZE_TECHNICAL - 1); windowTileInspectorToolMap.y = std::min(windowTileInspectorToolMap.y + 32, MAXIMUM_TILE_START_XY); window_tile_inspector_load_tile(w, nullptr); break; case WIDX_SPINNER_Y_DECREASE: - windowTileInspectorTileY = std::max(windowTileInspectorTileY - 1, 0); + windowTileInspectorTile.y = std::max(windowTileInspectorTile.y - 1, 0); windowTileInspectorToolMap.y = std::max(windowTileInspectorToolMap.y - 32, 0); window_tile_inspector_load_tile(w, nullptr); break; @@ -1274,8 +1274,7 @@ static void window_tile_inspector_update_selected_tile(rct_window* w, const Scre windowTileInspectorTileSelected = true; windowTileInspectorToolMap = mapCoords; - windowTileInspectorTileX = mapCoords.x >> 5; - windowTileInspectorTileY = mapCoords.y >> 5; + windowTileInspectorTile = TileCoordsXY(mapCoords); window_tile_inspector_load_tile(w, clickedElement); } diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index 741c828cf4..843bfce007 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -3887,6 +3887,10 @@ enum STR_HEAVY_SNOW = 6385, STR_BLIZZARD = 6386, + STR_CANT_LOWER_ELEMENT_HERE = 6387, + STR_CANT_RAISE_ELEMENT_HERE = 6388, + STR_NO_CLEARANCE = 6389, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings }; diff --git a/src/openrct2/windows/tile_inspector.h b/src/openrct2/windows/tile_inspector.h index 5ee93232f1..c85e0c7414 100644 --- a/src/openrct2/windows/tile_inspector.h +++ b/src/openrct2/windows/tile_inspector.h @@ -26,7 +26,6 @@ enum TILE_INSPECTOR_PAGE TILE_INSPECTOR_PAGE_CORRUPT }; -extern uint32_t windowTileInspectorTileX; -extern uint32_t windowTileInspectorTileY; +extern TileCoordsXY windowTileInspectorTile; extern int32_t windowTileInspectorElementCount; extern int32_t windowTileInspectorSelectedIndex; diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index ca380e402d..f234397d47 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -31,8 +31,7 @@ using namespace OpenRCT2; -uint32_t windowTileInspectorTileX; -uint32_t windowTileInspectorTileY; +TileCoordsXY windowTileInspectorTile; int32_t windowTileInspectorElementCount = 0; int32_t windowTileInspectorSelectedIndex; @@ -122,8 +121,7 @@ GameActionResult::Ptr tile_inspector_insert_corrupt_at(const CoordsXY& loc, int1 // 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 && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { windowTileInspectorElementCount++; @@ -224,8 +222,7 @@ GameActionResult::Ptr tile_inspector_remove_element_at(const CoordsXY& loc, int1 // Update the window rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { windowTileInspectorElementCount--; @@ -257,8 +254,7 @@ GameActionResult::Ptr tile_inspector_swap_elements_at(const CoordsXY& loc, int16 // Update the window rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { // If one of them was selected, update selected list item if (windowTileInspectorSelectedIndex == first) @@ -345,8 +341,7 @@ GameActionResult::Ptr tile_inspector_rotate_element_at(const CoordsXY& loc, int3 map_invalidate_tile_full(loc); - if (static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (loc == windowTileInspectorTile.ToCoordsXY()) { window_invalidate_by_class(WC_TILE_INSPECTOR); } @@ -396,8 +391,7 @@ GameActionResult::Ptr tile_inspector_paste_element_at(const CoordsXY& loc, TileE map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(tileLoc.x) == windowTileInspectorTileX - && static_cast(tileLoc.y) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && tileLoc == windowTileInspectorTile) { windowTileInspectorElementCount++; @@ -463,8 +457,7 @@ GameActionResult::Ptr tile_inspector_sort_elements_at(const CoordsXY& loc, bool // Deselect tile for clients who had it selected rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { windowTileInspectorSelectedIndex = -1; tileInspectorWindow->Invalidate(); @@ -474,6 +467,29 @@ GameActionResult::Ptr tile_inspector_sort_elements_at(const CoordsXY& loc, bool return std::make_unique(); } +static GameActionResult::Ptr 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(GA_ERROR::TOO_LOW, STR_CANT_LOWER_ELEMENT_HERE, STR_TOO_LOW); + } + else if (newBaseHeight > MAX_ELEMENT_HEIGHT) + { + return std::make_unique(GA_ERROR::TOO_HIGH, STR_CANT_RAISE_ELEMENT_HERE, STR_TOO_HIGH); + } + else if (newClearanceHeight < 0) + { + return std::make_unique(GA_ERROR::NO_CLEARANCE, STR_CANT_LOWER_ELEMENT_HERE, STR_NO_CLEARANCE); + } + else if (newClearanceHeight > MAX_ELEMENT_HEIGHT) + { + return std::make_unique(GA_ERROR::NO_CLEARANCE, STR_CANT_RAISE_ELEMENT_HERE, STR_NO_CLEARANCE); + } + return std::make_unique(); +} + GameActionResult::Ptr tile_inspector_any_base_height_offset( const CoordsXY& loc, int16_t elementIndex, int8_t heightOffset, bool isExecuting) { @@ -481,13 +497,9 @@ GameActionResult::Ptr tile_inspector_any_base_height_offset( if (tileElement == nullptr) return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - int16_t newBaseHeight = static_cast(tileElement->base_height + heightOffset); - int16_t newClearanceHeight = static_cast(tileElement->clearance_height + heightOffset); - if (newBaseHeight < 0 || newBaseHeight > MAX_ELEMENT_HEIGHT || newClearanceHeight < 0 - || newClearanceHeight > MAX_ELEMENT_HEIGHT) - { - return std::make_unique(GA_ERROR::UNKNOWN, STR_NONE); - } + auto heightValidationResult = ValidateTileHeight(tileElement, heightOffset); + if (heightValidationResult->Error != GA_ERROR::OK) + return heightValidationResult; if (isExecuting) { @@ -506,12 +518,10 @@ GameActionResult::Ptr tile_inspector_any_base_height_offset( 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) + 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.x == loc.x / 32 && exit.y == loc.y / 32 && exit.z == z) + 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 }); } } @@ -523,8 +533,7 @@ GameActionResult::Ptr tile_inspector_any_base_height_offset( map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -551,8 +560,7 @@ GameActionResult::Ptr tile_inspector_surface_show_park_fences(const CoordsXY& lo map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -618,8 +626,7 @@ GameActionResult::Ptr tile_inspector_surface_toggle_corner(const CoordsXY& loc, map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -656,8 +663,7 @@ GameActionResult::Ptr tile_inspector_surface_toggle_diagonal(const CoordsXY& loc map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -680,8 +686,7 @@ GameActionResult::Ptr tile_inspector_path_set_sloped(const CoordsXY& loc, int32_ map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -704,8 +709,7 @@ GameActionResult::Ptr tile_inspector_path_set_broken(const CoordsXY& loc, int32_ map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -730,8 +734,7 @@ GameActionResult::Ptr tile_inspector_path_toggle_edge( map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -772,8 +775,7 @@ GameActionResult::Ptr tile_inspector_entrance_make_usable(const CoordsXY& loc, i } rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -798,8 +800,7 @@ GameActionResult::Ptr tile_inspector_wall_set_slope( map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -824,8 +825,7 @@ GameActionResult::Ptr tile_inspector_wall_animation_frame_offset( map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -1057,8 +1057,7 @@ GameActionResult::Ptr tile_inspector_track_set_block_brake( map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -1082,8 +1081,7 @@ GameActionResult::Ptr tile_inspector_track_set_indestructible( map_invalidate_tile_full(loc); rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR); - if (tileInspectorWindow != nullptr && static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (tileInspectorWindow != nullptr && loc == windowTileInspectorTile.ToCoordsXY()) { tileInspectorWindow->Invalidate(); } @@ -1109,8 +1107,7 @@ GameActionResult::Ptr tile_inspector_scenery_set_quarter_location( tileElement->SetOccupiedQuadrants(1 << ((quarterIndex + 2) & 3)); map_invalidate_tile_full(loc); - if (static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (loc == windowTileInspectorTile.ToCoordsXY()) { window_invalidate_by_class(WC_TILE_INSPECTOR); } @@ -1134,8 +1131,7 @@ GameActionResult::Ptr tile_inspector_scenery_set_quarter_collision( tileElement->SetOccupiedQuadrants(occupiedQuadrants); map_invalidate_tile_full(loc); - if (static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (loc == windowTileInspectorTile.ToCoordsXY()) { window_invalidate_by_class(WC_TILE_INSPECTOR); } @@ -1158,8 +1154,7 @@ GameActionResult::Ptr tile_inspector_banner_toggle_blocking_edge( edges ^= (1 << edgeIndex); bannerElement->AsBanner()->SetAllowedEdges(edges); - if (static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (loc == windowTileInspectorTile.ToCoordsXY()) { window_invalidate_by_class(WC_TILE_INSPECTOR); } @@ -1183,8 +1178,7 @@ GameActionResult::Ptr tile_inspector_corrupt_clamp(const CoordsXY& loc, int32_t TileElement* const nextElement = corruptElement + 1; corruptElement->base_height = corruptElement->clearance_height = nextElement->base_height; - if (static_cast(loc.x / 32) == windowTileInspectorTileX - && static_cast(loc.y / 32) == windowTileInspectorTileY) + if (loc == windowTileInspectorTile.ToCoordsXY()) { window_invalidate_by_class(WC_TILE_INSPECTOR); }