diff --git a/distribution/changelog.txt b/distribution/changelog.txt index ebe5217672..c230d85318 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -15,7 +15,8 @@ - Fix: [#7176] Mechanics sometimes fall down from rides. - Fix: [#7303] Visual glitch with virtual floor near map edges. - Fix: [#7327] Abstract scenery and stations don't get fully See-Through when hiding them (original bug). -- Fix: [#7382] Opening the mini-map reverts the size of the land tool to 1x1, regardless of what was selected before. +- Fix: [#7382] Opening the mini-map reverts the size of the land tool to 1x1, regardless of what was selected before. +- Fix: [#7402] Edges of neigbouring footpaths stay connected after removing a path that's underneath a ride entrance. - Fix: Cut-away view does not draw tile elements that have been moved down on the list. - Improved: [#2989] Multiplayer window now changes title when tab changes. - Improved: [#5339] Change eyedropper icon to actual eyedropper and change cursor to crosshair. diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index bffb3ddb58..641695a1fb 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -2256,7 +2256,7 @@ static void footpath_remove_edges_towards(sint32 x, sint32 y, sint32 z0, sint32 // Returns true when there is an element at the given coordinates that want to connect to a path with the given direction (ride // entrances and exits, shops, paths). -static bool tile_element_wants_path_connection_towards(TileCoordsXYZD coords, const rct_tile_element * const elementToBeRemoved) +bool tile_element_wants_path_connection_towards(TileCoordsXYZD coords, const rct_tile_element * const elementToBeRemoved) { rct_tile_element * tileElement = map_get_first_element_at(coords.x, coords.y); do @@ -2299,15 +2299,21 @@ static bool tile_element_wants_path_connection_towards(TileCoordsXYZD coords, co uint16 dx = ((coords.direction - tile_element_get_direction(tileElement)) & TILE_ELEMENT_DIRECTION_MASK); if (FlatRideTrackSequenceProperties[trackType][trackSequence] & (1 << dx)) { - // Track element has the flags required for + // Track element has the flags required for the given direction return true; } } } break; case TILE_ELEMENT_TYPE_ENTRANCE: - if (entrance_has_direction(tileElement, coords.direction - tile_element_get_direction(tileElement))) - return true; + if (tileElement->base_height == coords.z) + { + if (entrance_has_direction(tileElement, coords.direction - tile_element_get_direction(tileElement))) + { + // Entrance wants to be connected towards the given direction + return true; + } + } break; default: break; diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index d5406dd2e0..c514d2b324 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -524,6 +524,7 @@ void tile_element_set_banner_index(rct_tile_element * tileElement, sint32 banner void tile_element_remove_banner_entry(rct_tile_element *tileElement); bool tile_element_is_underground(rct_tile_element *tileElement); +bool tile_element_wants_path_connection_towards(TileCoordsXYZD coords, const rct_tile_element * const elementToBeRemoved); void map_remove_out_of_range_elements(); void map_extend_boundary_surface(); diff --git a/test/tests/CMakeLists.txt b/test/tests/CMakeLists.txt index 01e5b5bd43..c87ff62982 100644 --- a/test/tests/CMakeLists.txt +++ b/test/tests/CMakeLists.txt @@ -153,3 +153,10 @@ set(MULTILAUNCH_TEST_SOURCES "${CMAKE_CURRENT_LIST_DIR}/MultiLaunch.cpp" add_executable(test_multilaunch ${MULTILAUNCH_TEST_SOURCES}) target_link_libraries(test_multilaunch ${GTEST_LIBRARIES} libopenrct2 ${LDL} z) add_test(NAME multilaunch COMMAND test_multilaunch) + +# Tile element test +set(TILE_ELEMENT_TEST_SOURCES "${CMAKE_CURRENT_LIST_DIR}/TileElements.cpp" + "${CMAKE_CURRENT_LIST_DIR}/TestData.cpp") +add_executable(test_tile_elements ${TILE_ELEMENT_TEST_SOURCES}) +target_link_libraries(test_tile_elements ${GTEST_LIBRARIES} libopenrct2 ${LDL} z) +add_test(NAME tile_elements COMMAND test_tile_elements) diff --git a/test/tests/TileElements.cpp b/test/tests/TileElements.cpp new file mode 100644 index 0000000000..37d57dad6d --- /dev/null +++ b/test/tests/TileElements.cpp @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include +#include +#include "TestData.h" + +using namespace OpenRCT2; + +class TileElementWantsFootpathConnection : public testing::Test +{ +protected: + static void SetUpTestCase() + { + std::string parkPath = TestData::GetParkPath("tile-element-tests.sv6"); + gOpenRCT2Headless = true; + gOpenRCT2NoGraphics = true; + _context = CreateContext(); + bool initialised = _context->Initialise(); + ASSERT_TRUE(initialised); + + ParkLoadResult * plr = load_from_sv6(parkPath.c_str()); + ASSERT_EQ(ParkLoadResult_GetError(plr), PARK_LOAD_ERROR_OK); + ParkLoadResult_Delete(plr); + game_load_init(); + SUCCEED(); + } + + static void TearDownTestCase() + { + delete _context; + _context = nullptr; + SUCCEED(); + } + +private: + static IContext * _context; +}; + +IContext * TileElementWantsFootpathConnection::_context = nullptr; + +TEST_F(TileElementWantsFootpathConnection, FlatPath) +{ + // Flat paths want to connect to other paths in any direction + const rct_tile_element * const pathElement = map_get_footpath_element(19, 18, 14); + ASSERT_NE(pathElement, nullptr); + EXPECT_TRUE(tile_element_wants_path_connection_towards({ 19, 18, 14, 0 }, nullptr)); + EXPECT_TRUE(tile_element_wants_path_connection_towards({ 19, 18, 14, 1 }, nullptr)); + EXPECT_TRUE(tile_element_wants_path_connection_towards({ 19, 18, 14, 2 }, nullptr)); + EXPECT_TRUE(tile_element_wants_path_connection_towards({ 19, 18, 14, 3 }, nullptr)); + SUCCEED(); +} + +TEST_F(TileElementWantsFootpathConnection, SlopedPath) +{ + // Sloped paths only want to connect in two directions, of which is one at a higher offset + const rct_tile_element * const slopedPathElement = map_get_footpath_element(18, 18, 14); + ASSERT_NE(slopedPathElement, nullptr); + ASSERT_TRUE(footpath_element_is_sloped(slopedPathElement)); + // Bottom and top of sloped path want a path connection + EXPECT_TRUE(tile_element_wants_path_connection_towards({ 18, 18, 14, 2 }, nullptr)); + EXPECT_TRUE(tile_element_wants_path_connection_towards({ 18, 18, 16, 0 }, nullptr)); + // Other directions at both heights do not want a connection + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 18, 14, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 18, 14, 1 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 18, 14, 3 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 18, 16, 1 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 18, 16, 2 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 18, 16, 3 }, nullptr)); + SUCCEED(); +} + +TEST_F(TileElementWantsFootpathConnection, Stall) +{ + // Stalls usually have one path direction flag, but can have multiple (info kiosk for example) + const rct_tile_element * const stallElement = map_get_track_element_at(19 << 5, 15 << 5, 14); + ASSERT_NE(stallElement, nullptr); + EXPECT_TRUE(tile_element_wants_path_connection_towards({ 19, 15, 14, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 15, 14, 1 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 15, 14, 2 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 15, 14, 3 }, nullptr)); + SUCCEED(); +} + +TEST_F(TileElementWantsFootpathConnection, RideEntrance) +{ + // Ride entrances and exits want a connection in one direction + const rct_tile_element * const entranceElement = map_get_ride_entrance_element_at(18 << 5, 8 << 5, 14, false); + ASSERT_NE(entranceElement, nullptr); + EXPECT_TRUE(tile_element_wants_path_connection_towards({ 18, 8, 14, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 8, 14, 1 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 8, 14, 2 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 8, 14, 3 }, nullptr)); + SUCCEED(); +} + +TEST_F(TileElementWantsFootpathConnection, RideExit) +{ + // The exit has been rotated; it wants a path connection in direction 1, but not 0 like the entrance + const rct_tile_element * const exitElement = map_get_ride_exit_element_at(18 << 5, 10 << 5, 14, false); + ASSERT_NE(exitElement, nullptr); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 10, 14, 0 }, nullptr)); + EXPECT_TRUE(tile_element_wants_path_connection_towards({ 18, 10, 14, 1 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 10, 14, 2 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 10, 14, 3 }, nullptr)); + SUCCEED(); +} + +TEST_F(TileElementWantsFootpathConnection, DifferentHeight) +{ + // Test at different heights, all of these should fail + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 18, 4, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 18, 4, 1 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 18, 4, 2 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 18, 4, 3 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 18, 4, 2 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 18, 6, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 15, 4, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 8, 4, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 10, 4, 1 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 18, 24, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 18, 24, 1 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 18, 24, 2 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 18, 24, 3 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 18, 24, 2 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 18, 26, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 19, 15, 24, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 8, 24, 0 }, nullptr)); + EXPECT_FALSE(tile_element_wants_path_connection_towards({ 18, 10, 24, 1 }, nullptr)); + SUCCEED(); +} diff --git a/test/tests/testdata/parks/tile-element-tests.sv6 b/test/tests/testdata/parks/tile-element-tests.sv6 new file mode 100644 index 0000000000..de2fa86176 Binary files /dev/null and b/test/tests/testdata/parks/tile-element-tests.sv6 differ diff --git a/test/tests/tests.vcxproj b/test/tests/tests.vcxproj index a2b91b3921..9fd921b000 100644 --- a/test/tests/tests.vcxproj +++ b/test/tests/tests.vcxproj @@ -65,6 +65,7 @@ + \ No newline at end of file