From 195de3b25830b7ce21fdf243ada9da88307f9d07 Mon Sep 17 00:00:00 2001 From: mix Date: Mon, 3 Nov 2025 01:05:23 +0000 Subject: [PATCH] Fix #6228: Track design queue connections not preserved when built --- distribution/changelog.txt | 1 + src/openrct2/ride/Ride.h | 3 ++- src/openrct2/ride/TrackDesign.cpp | 18 +++++++------ src/openrct2/world/Footpath.cpp | 45 +++++++++++++++++++++++++++++++ src/openrct2/world/Footpath.h | 1 + 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index cde2c4bf64..4571da31ab 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,6 +1,7 @@ 0.4.29 (in development) ------------------------------------------------------------------------ - Improved: [#25426] Building the track designs index is now quicker. +- Fix: [#6228] The saved queue line path connections are not preserved when placing track designs (original bug). - Fix: [#14365] Track designs with scenery below the lowest track piece do not preview correctly. - Fix: [#25451] Dropdown item tooltips stay open if the mouse is moved over an empty space. - Fix: [#25461] Path connections in raised track designs are sometimes broken when placed. diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index 3bcef56b5e..d544932ce6 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -327,13 +327,14 @@ public: // in the station array. e.g. if only slot 0 and 2 are in use, index 2 returns 2 instead of 3. StationIndex::UnderlyingType getStationNumber(StationIndex in) const; + void chainQueues() const; + private: void update(); void updateQueueLength(StationIndex stationIndex); ResultWithMessage createVehicles(const CoordsXYE& element, bool isApplying, bool isSimulating); void moveTrainsToBlockBrakes(const CoordsXYZ& firstBlockPosition, OpenRCT2::TrackElement& firstBlock); money64 calculateIncomePerHour() const; - void chainQueues() const; void constructMissingEntranceOrExit() const; ResultWithMessage changeStatusDoStationChecks(StationIndex& stationIndex); diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index bb07e65998..3c010d5719 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -1229,12 +1229,6 @@ static GameActions::Result TrackDesignPlaceSceneryElement( return GameActions::Result(); } - if (tds.placeOperation == TrackPlaceOperation::place) - { - FootpathQueueChainReset(); - FootpathRemoveEdgesAt(mapCoord, reinterpret_cast(pathElement)); - } - flags = GAME_COMMAND_FLAG_APPLY; if (tds.placeOperation == TrackPlaceOperation::placeTrackPreview) { @@ -1252,8 +1246,11 @@ static GameActions::Result TrackDesignPlaceSceneryElement( if (tds.placeOperation == TrackPlaceOperation::place) { - FootpathConnectEdges(mapCoord, reinterpret_cast(pathElement), flags); - FootpathUpdateQueueChains(); + if (!pathElement->IsQueue() || FootpathQueueCountConnections(mapCoord, *pathElement) < 2) + { + FootpathRemoveEdgesAt(mapCoord, reinterpret_cast(pathElement)); + FootpathConnectEdges(mapCoord, reinterpret_cast(pathElement), flags); + } } return GameActions::Result(); @@ -1807,6 +1804,11 @@ static GameActions::Result TrackDesignPlaceVirtual( return sceneryPlaceRes; } + if (tds.placeOperation == TrackPlaceOperation::place || tds.placeOperation == TrackPlaceOperation::placeTrackPreview) + { + ride.chainQueues(); + } + // 0x6D0FE6 if (tds.placeOperation == TrackPlaceOperation::drawOutlines) { diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 43f754812d..57a5bdf1e3 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -955,6 +955,51 @@ void FootpathUpdateQueueChains() } } +int32_t FootpathQueueCountConnections(const CoordsXY& position, const PathElement& pathElement) +{ + int32_t connectionCount = 0; + for (const Direction direction : kAllDirections) + { + const uint8_t edge = 1 << direction; + if (pathElement.GetEdges() & edge) + { + const CoordsXY adjacentPathPosition = position + CoordsDirectionDelta[direction]; + const int32_t z = pathElement.GetBaseZ(); + const TileElement* tileElement = FootpathGetElement({ adjacentPathPosition, z, z + kLandHeightStep }, direction); + + if (tileElement == nullptr) + { + tileElement = FootpathGetElement({ adjacentPathPosition, z - kLandHeightStep, z }, direction); + + if (tileElement == nullptr) + { + const EntranceElement* entrance = MapGetRideEntranceElementAt(CoordsXYZ{ adjacentPathPosition, z }, true); + if (entrance == nullptr) + { + entrance = MapGetRideEntranceElementAt(CoordsXYZ{ adjacentPathPosition, z + kLandHeightStep }, true); + if (entrance == nullptr) + continue; + } + + if (entrance_has_direction(*entrance, direction + entrance->GetDirection())) + { + connectionCount++; + } + continue; + } + } + + const PathElement& adjacentPath = *tileElement->AsPath(); + + if (adjacentPath.GetEdges() & Numerics::rol4(edge, 2)) + { + connectionCount++; + } + } + } + return connectionCount; +} + /** * * rct2: 0x0069ADBD diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index 9690d468f8..9fa7c8e188 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -189,6 +189,7 @@ const OpenRCT2::FootpathRailingsObject* GetPathRailingsEntry(OpenRCT2::ObjectEnt void FootpathQueueChainReset(); void FootpathQueueChainPush(RideId rideIndex); +int32_t FootpathQueueCountConnections(const CoordsXY& position, const OpenRCT2::PathElement& pathElement); bool FootpathIsZAndDirectionValid(const OpenRCT2::PathElement& tileElement, int32_t currentZ, int32_t currentDirection); FootpathPlacementResult FootpathGetOnTerrainPlacement(const TileCoordsXY& location);