diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index f4f4c4b35d..54efa75b23 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -51,7 +51,7 @@ using namespace OpenRCT2::Numerics; namespace OpenRCT2::Ui::Windows { static money64 FootpathProvisionalSet( - ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope, + ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, FootpathSlope slope, PathConstructFlags constructFlags); enum class PathConstructionMode : uint8_t @@ -82,7 +82,7 @@ namespace OpenRCT2::Ui::Windows { ObjectEntryIndex type; CoordsXYZ position; - uint8_t slope; + FootpathSlope slope; ProvisionalPathFlags flags; ObjectEntryIndex surfaceIndex; ObjectEntryIndex railingsIndex; @@ -533,7 +533,7 @@ namespace OpenRCT2::Ui::Windows FootpathPlacementResult FootpathGetPlacementFromScreenCoords(const ScreenCoordsXY& screenCoords) { if (_footpathPlaceZ > 0) - return { _footpathPlaceZ, kTileSlopeFlat }; + return { _footpathPlaceZ, {} }; auto info = GetMapCoordinatesFromPos( screenCoords, EnumsToFlags(ViewportInteractionItem::terrain, ViewportInteractionItem::footpath)); @@ -566,7 +566,7 @@ namespace OpenRCT2::Ui::Windows ObjectEntryIndex railings = gFootpathSelection.Railings; CoordsXYZ footpathLoc; - int32_t slope; + FootpathSlope slope; FootpathGetNextPathInfo(&type, footpathLoc, &slope); auto pathConstructFlags = FootpathCreateConstructFlags(type); @@ -583,7 +583,7 @@ namespace OpenRCT2::Ui::Windows _provisionalFootpath.flags.flip(ProvisionalPathFlag::showArrow); CoordsXYZ footpathLoc; - int32_t slope; + FootpathSlope slope; FootpathGetNextPathInfo(nullptr, footpathLoc, &slope); gMapSelectArrowPosition = footpathLoc; gMapSelectArrowDirection = _footpathConstructDirection; @@ -946,10 +946,11 @@ namespace OpenRCT2::Ui::Windows auto pathElement = info.Element->AsPath(); if (pathElement != nullptr) { - auto slope = pathElement->GetSlopeDirection(); + auto slopeDirection = pathElement->GetSlopeDirection(); + FootpathSlope slope = { FootpathSlopeType::flat, slopeDirection }; if (pathElement->IsSloped()) { - slope |= FOOTPATH_PROPERTIES_FLAG_IS_SLOPED; + slope.type = FootpathSlopeType::sloped; } return { pathElement->GetBaseZ(), slope }; } @@ -1166,7 +1167,7 @@ namespace OpenRCT2::Ui::Windows FootpathUpdateProvisional(); ObjectEntryIndex type; - int32_t slope; + FootpathSlope slope; CoordsXYZ footpathLoc; FootpathGetNextPathInfo(&type, footpathLoc, &slope); @@ -1416,7 +1417,7 @@ namespace OpenRCT2::Ui::Windows * * rct2: 0x006A7B20 */ - void FootpathGetNextPathInfo(ObjectEntryIndex* type, CoordsXYZ& footpathLoc, int32_t* slope) + void FootpathGetNextPathInfo(ObjectEntryIndex* type, CoordsXYZ& footpathLoc, FootpathSlope* slope) { auto direction = _footpathConstructDirection; footpathLoc.x = _footpathConstructFromPosition.x + CoordsDirectionDelta[direction].x; @@ -1426,14 +1427,14 @@ namespace OpenRCT2::Ui::Windows { *type = gFootpathSelection.GetSelectedSurface(); } - *slope = kTileSlopeFlat; + *slope = {}; if (_footpathConstructSlope != 0) { - *slope = _footpathConstructDirection | kTileSlopeSCornerUp; + *slope = { FootpathSlopeType::sloped, _footpathConstructDirection }; if (_footpathConstructSlope != 2) { footpathLoc.z -= kPathHeightStep; - *slope ^= kTileSlopeECornerUp; + slope->direction = DirectionReverse(slope->direction); } } } @@ -1686,7 +1687,7 @@ namespace OpenRCT2::Ui::Windows * rct2: 0x006A76FF */ static money64 FootpathProvisionalSet( - ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope, + ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, FootpathSlope slope, PathConstructFlags constructFlags) { FootpathRemoveProvisional(); @@ -1725,7 +1726,7 @@ namespace OpenRCT2::Ui::Windows VirtualFloorSetHeight(0); } else if ( - _provisionalFootpath.slope == kTileSlopeFlat + _provisionalFootpath.slope.type == FootpathSlopeType::flat || _provisionalFootpath.position.z < _footpathConstructFromPosition.z) { // Going either straight on, or down. diff --git a/src/openrct2/actions/FootpathLayoutPlaceAction.cpp b/src/openrct2/actions/FootpathLayoutPlaceAction.cpp index 61b38aca1a..0b6aa37e9c 100644 --- a/src/openrct2/actions/FootpathLayoutPlaceAction.cpp +++ b/src/openrct2/actions/FootpathLayoutPlaceAction.cpp @@ -30,7 +30,7 @@ namespace OpenRCT2::GameActions { FootpathLayoutPlaceAction::FootpathLayoutPlaceAction( - const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, uint8_t edges, + const CoordsXYZ& loc, FootpathSlope slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, uint8_t edges, PathConstructFlags constructFlags) : _loc(loc) , _slope(slope) @@ -52,7 +52,8 @@ namespace OpenRCT2::GameActions void FootpathLayoutPlaceAction::AcceptParameters(GameActionParameterVisitor& visitor) { visitor.Visit(_loc); - visitor.Visit("slope", _slope); + visitor.Visit("slopeType", _slope.type); + visitor.Visit("slopeDirection", _slope.direction); visitor.Visit("object", _type); visitor.Visit("railingsObject", _railingsType); visitor.Visit("edges", _edges); @@ -131,9 +132,9 @@ namespace OpenRCT2::GameActions QuarterTile quarterTile{ 0b1111, 0 }; auto zLow = _loc.z; auto zHigh = zLow + kPathClearance; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + if (_slope.type == FootpathSlopeType::sloped) { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask); + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope.direction); zHigh += kPathHeightStep; } @@ -151,8 +152,8 @@ namespace OpenRCT2::GameActions // Do not attempt to build a crossing with a queue or a sloped path. auto isQueue = _constructFlags & PathConstructFlag::IsQueue; - auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none - : CreateCrossingMode::pathOverTrack; + auto crossingMode = isQueue || (_slope.type != FootpathSlopeType::flat) ? CreateCrossingMode::none + : CreateCrossingMode::pathOverTrack; auto canBuild = MapCanConstructWithClearAt( { _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GetFlags(), kTileSlopeFlat, crossingMode); if (!entrancePath && canBuild.Error != Status::Ok) @@ -200,9 +201,9 @@ namespace OpenRCT2::GameActions QuarterTile quarterTile{ 0b1111, 0 }; auto zLow = _loc.z; auto zHigh = zLow + kPathClearance; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + if (_slope.type == FootpathSlopeType::sloped) { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask); + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope.direction); zHigh += kPathHeightStep; } @@ -220,8 +221,8 @@ namespace OpenRCT2::GameActions // Do not attempt to build a crossing with a queue or a sloped path. auto isQueue = _constructFlags & PathConstructFlag::IsQueue; - auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none - : CreateCrossingMode::pathOverTrack; + auto crossingMode = isQueue || (_slope.type != FootpathSlopeType::flat) ? CreateCrossingMode::none + : CreateCrossingMode::pathOverTrack; auto canBuild = MapCanConstructWithClearAt( { _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), kTileSlopeFlat, crossingMode); @@ -274,8 +275,8 @@ namespace OpenRCT2::GameActions pathElement->SetSurfaceEntryIndex(_type); pathElement->SetRailingsEntryIndex(_railingsType); } - pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); - pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED); + pathElement->SetSlopeDirection(_slope.direction); + pathElement->SetSloped(_slope.type == FootpathSlopeType::sloped); pathElement->SetIsQueue(isQueue); pathElement->SetAddition(0); pathElement->SetRideIndex(RideId::GetNull()); diff --git a/src/openrct2/actions/FootpathLayoutPlaceAction.h b/src/openrct2/actions/FootpathLayoutPlaceAction.h index 9a08ecd0a5..c971241c4d 100644 --- a/src/openrct2/actions/FootpathLayoutPlaceAction.h +++ b/src/openrct2/actions/FootpathLayoutPlaceAction.h @@ -18,7 +18,7 @@ namespace OpenRCT2::GameActions { private: CoordsXYZ _loc; - uint8_t _slope{}; + FootpathSlope _slope{}; ObjectEntryIndex _type{}; ObjectEntryIndex _railingsType{}; uint8_t _edges{}; @@ -27,7 +27,7 @@ namespace OpenRCT2::GameActions public: FootpathLayoutPlaceAction() = default; FootpathLayoutPlaceAction( - const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, uint8_t edges, + const CoordsXYZ& loc, FootpathSlope slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, uint8_t edges, PathConstructFlags constructFlags = 0); void AcceptParameters(GameActionParameterVisitor&) final; diff --git a/src/openrct2/actions/FootpathPlaceAction.cpp b/src/openrct2/actions/FootpathPlaceAction.cpp index 701f24a7c6..a9f28f074c 100644 --- a/src/openrct2/actions/FootpathPlaceAction.cpp +++ b/src/openrct2/actions/FootpathPlaceAction.cpp @@ -39,7 +39,7 @@ namespace OpenRCT2::GameActions { FootpathPlaceAction::FootpathPlaceAction( - const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, Direction direction, + const CoordsXYZ& loc, FootpathSlope slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, Direction direction, PathConstructFlags constructFlags) : _loc(loc) , _slope(slope) @@ -56,7 +56,8 @@ namespace OpenRCT2::GameActions visitor.Visit("object", _type); visitor.Visit("railingsObject", _railingsType); visitor.Visit("direction", _direction); - visitor.Visit("slope", _slope); + visitor.Visit("slopeType", _slope.type); + visitor.Visit("slopeDirection", _slope.direction); visitor.Visit("constructFlags", _constructFlags); } @@ -92,7 +93,7 @@ namespace OpenRCT2::GameActions return Result(Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_NOT_OWNED_BY_PARK); } - if (_slope & SLOPE_IS_IRREGULAR_FLAG) + if (_slope.type == FootpathSlopeType::irregular || _slope.type == FootpathSlopeType::raise) { return Result(Status::Disallowed, STR_CANT_BUILD_FOOTPATH_HERE, STR_LAND_SLOPE_UNSUITABLE); } @@ -116,7 +117,7 @@ namespace OpenRCT2::GameActions auto intent = Intent(INTENT_ACTION_REMOVE_PROVISIONAL_FOOTPATH); ContextBroadcastIntent(&intent); - auto tileElement = MapGetFootpathElementSlope(_loc, _slope); + auto tileElement = MapGetFootpathElementWithSlope(_loc, _slope); if (tileElement == nullptr) { return ElementInsertQuery(std::move(res)); @@ -149,14 +150,15 @@ namespace OpenRCT2::GameActions auto zLow = _loc.z; auto zHigh = zLow + kPathClearance; WallRemoveIntersectingWalls( - { _loc, zLow, zHigh + ((_slope & kTileSlopeRaisedCornersMask) ? 16 : 0) }, DirectionReverse(_direction)); + { _loc, zLow, zHigh + ((_slope.type == FootpathSlopeType::sloped) ? 16 : 0) }, + DirectionReverse(_direction)); WallRemoveIntersectingWalls( { _loc.x - CoordsDirectionDelta[_direction].x, _loc.y - CoordsDirectionDelta[_direction].y, zLow, zHigh }, _direction); } } - auto tileElement = MapGetFootpathElementSlope(_loc, _slope); + auto tileElement = MapGetFootpathElementWithSlope(_loc, _slope); if (tileElement == nullptr) { return ElementInsertExecute(std::move(res)); @@ -295,9 +297,9 @@ namespace OpenRCT2::GameActions QuarterTile quarterTile{ 0b1111, 0 }; auto zLow = _loc.z; auto zHigh = zLow + kPathClearance; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + if (_slope.type == FootpathSlopeType::sloped) { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask); + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope.direction); zHigh += kPathHeightStep; } @@ -315,8 +317,8 @@ namespace OpenRCT2::GameActions // Do not attempt to build a crossing with a queue or a sloped path. auto isQueue = _constructFlags & PathConstructFlag::IsQueue; - auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none - : CreateCrossingMode::pathOverTrack; + auto crossingMode = isQueue || (_slope.type != FootpathSlopeType::flat) ? CreateCrossingMode::none + : CreateCrossingMode::pathOverTrack; auto canBuild = MapCanConstructWithClearAt( { _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GetFlags(), kTileSlopeFlat, crossingMode); if (!entrancePath && canBuild.Error != Status::Ok) @@ -363,9 +365,9 @@ namespace OpenRCT2::GameActions QuarterTile quarterTile{ 0b1111, 0 }; auto zLow = _loc.z; auto zHigh = zLow + kPathClearance; - if (_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED) + if (_slope.type == FootpathSlopeType::sloped) { - quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope & kTileElementDirectionMask); + quarterTile = QuarterTile{ 0b1111, 0b1100 }.Rotate(_slope.direction); zHigh += kPathHeightStep; } @@ -383,8 +385,8 @@ namespace OpenRCT2::GameActions // Do not attempt to build a crossing with a queue or a sloped. auto isQueue = _constructFlags & PathConstructFlag::IsQueue; - auto crossingMode = isQueue || (_slope != kTileSlopeFlat) ? CreateCrossingMode::none - : CreateCrossingMode::pathOverTrack; + auto crossingMode = isQueue || (_slope.type != FootpathSlopeType::flat) ? CreateCrossingMode::none + : CreateCrossingMode::pathOverTrack; auto canBuild = MapCanConstructWithClearAt( { _loc, zLow, zHigh }, &MapPlaceNonSceneryClearFunc, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), kTileSlopeFlat, crossingMode); @@ -436,8 +438,8 @@ namespace OpenRCT2::GameActions pathElement->SetSurfaceEntryIndex(_type); pathElement->SetRailingsEntryIndex(_railingsType); } - pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); - pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED); + pathElement->SetSlopeDirection(_slope.direction); + pathElement->SetSloped(_slope.type == FootpathSlopeType::sloped); pathElement->SetIsQueue(isQueue); pathElement->SetAddition(0); pathElement->SetRideIndex(RideId::GetNull()); @@ -525,10 +527,9 @@ namespace OpenRCT2::GameActions MapInvalidateTileFull(_loc); } - PathElement* FootpathPlaceAction::MapGetFootpathElementSlope(const CoordsXYZ& footpathPos, int32_t slope) const + PathElement* FootpathPlaceAction::MapGetFootpathElementWithSlope(const CoordsXYZ& footpathPos, FootpathSlope slope) const { - const bool isSloped = slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED; - const auto slopeDirection = slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK; + const bool isSloped = slope.type == FootpathSlopeType::sloped; for (auto* pathElement : TileElementsView(footpathPos)) { @@ -536,7 +537,7 @@ namespace OpenRCT2::GameActions continue; if (pathElement->IsSloped() != isSloped) continue; - if (pathElement->GetSlopeDirection() != slopeDirection) + if (pathElement->GetSlopeDirection() != slope.direction) continue; return pathElement; } diff --git a/src/openrct2/actions/FootpathPlaceAction.h b/src/openrct2/actions/FootpathPlaceAction.h index c474acd042..325e139766 100644 --- a/src/openrct2/actions/FootpathPlaceAction.h +++ b/src/openrct2/actions/FootpathPlaceAction.h @@ -18,7 +18,7 @@ namespace OpenRCT2::GameActions { private: CoordsXYZ _loc; - uint8_t _slope{}; + FootpathSlope _slope{}; ObjectEntryIndex _type{}; ObjectEntryIndex _railingsType{}; Direction _direction{ kInvalidDirection }; @@ -27,7 +27,7 @@ namespace OpenRCT2::GameActions public: FootpathPlaceAction() = default; FootpathPlaceAction( - const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, + const CoordsXYZ& loc, FootpathSlope slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, Direction direction = kInvalidDirection, PathConstructFlags constructFlags = 0); void AcceptParameters(GameActionParameterVisitor&) final; @@ -44,7 +44,7 @@ namespace OpenRCT2::GameActions Result ElementInsertExecute(Result res) const; void AutomaticallySetPeepSpawn() const; void RemoveIntersectingWalls(PathElement* pathElement) const; - PathElement* MapGetFootpathElementSlope(const CoordsXYZ& footpathPos, int32_t slope) const; + PathElement* MapGetFootpathElementWithSlope(const CoordsXYZ& footpathPos, FootpathSlope slope) const; bool IsSameAsPathElement(const PathElement* pathElement) const; bool IsSameAsEntranceElement(const EntranceElement& entranceElement) const; }; diff --git a/src/openrct2/core/DataSerialiserTraits.h b/src/openrct2/core/DataSerialiserTraits.h index a3dcf27304..01e9af91c6 100644 --- a/src/openrct2/core/DataSerialiserTraits.h +++ b/src/openrct2/core/DataSerialiserTraits.h @@ -17,6 +17,7 @@ #include "../ride/RideColour.h" #include "../ride/TrackDesign.h" #include "../world/Banner.h" +#include "../world/Footpath.h" #include "../world/Location.hpp" #include "../world/tile_element/TileElement.h" #include "DataSerialiserTag.h" @@ -989,3 +990,28 @@ struct DataSerializerTraitsT stream->Write(msg, strlen(msg)); } }; + +template<> +struct DataSerializerTraitsT +{ + static void encode(OpenRCT2::IStream* stream, const FootpathSlope& slope) + { + uint8_t combined = (EnumValue(slope.type) << 2) | (slope.direction % kNumOrthogonalDirections); + stream->WriteValue(combined); + } + + static void decode(OpenRCT2::IStream* stream, FootpathSlope& slope) + { + auto combined = stream->ReadValue(); + auto type = static_cast(combined >> 2); + Direction direction = combined & 0b00000011; + slope = FootpathSlope{ type, direction }; + } + + static void log(OpenRCT2::IStream* stream, const FootpathSlope& slope) + { + char msg[128] = {}; + snprintf(msg, sizeof(msg), "FootpathSlope(type = %d, direction = %d)", EnumValue(slope.type), slope.direction); + stream->Write(msg, strlen(msg)); + } +}; diff --git a/src/openrct2/paint/tile_element/Paint.Path.cpp b/src/openrct2/paint/tile_element/Paint.Path.cpp index e740ff2e70..072200084d 100644 --- a/src/openrct2/paint/tile_element/Paint.Path.cpp +++ b/src/openrct2/paint/tile_element/Paint.Path.cpp @@ -194,7 +194,7 @@ static void PathPaintSlopedFences( PaintSession& session, const PathElement& pathElement, uint16_t height, ImageId imageId, bool isQueue) { auto queueOffset = isQueue ? 14 : 0; - switch ((pathElement.GetSlopeDirection() + session.CurrentRotation) & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK) + switch ((pathElement.GetSlopeDirection() + session.CurrentRotation) % kNumOrthogonalDirections) { case 0: PaintAddImageAsParent( @@ -630,7 +630,7 @@ static void PathPaintFencesAdditionsTunnels( } // This is about tunnel drawing - uint8_t direction = (pathElement.GetSlopeDirection() + session.CurrentRotation) & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK; + uint8_t direction = (pathElement.GetSlopeDirection() + session.CurrentRotation) % kNumOrthogonalDirections; bool sloped = pathElement.IsSloped(); if (connectedEdges & EDGE_SE) @@ -864,8 +864,7 @@ static ImageIndex PathPaintGetBaseImage( ImageIndex surfaceBaseImageIndex = pathPaintInfo.SurfaceImageId; if (pathElement.IsSloped()) { - auto directionOffset = (pathElement.GetSlopeDirection() + session.CurrentRotation) - & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK; + auto directionOffset = (pathElement.GetSlopeDirection() + session.CurrentRotation) % kNumOrthogonalDirections; surfaceBaseImageIndex += 16 + directionOffset; } else @@ -973,8 +972,7 @@ void PathPaintBoxSupport( ImageIndex bridgeBaseImageIndex; if (pathElement.IsSloped()) { - auto directionOffset = (pathElement.GetSlopeDirection() + session.CurrentRotation) - & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK; + auto directionOffset = (pathElement.GetSlopeDirection() + session.CurrentRotation) % kNumOrthogonalDirections; bridgeBaseImageIndex = pathPaintInfo.BridgeImageId + 51 + directionOffset; } else @@ -1028,8 +1026,7 @@ void PathPaintPoleSupport( ImageIndex bridgeBaseImageIndex; if (pathElement.IsSloped()) { - bridgeBaseImageIndex = ((pathElement.GetSlopeDirection() + session.CurrentRotation) - & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK) + bridgeBaseImageIndex = ((pathElement.GetSlopeDirection() + session.CurrentRotation) % kNumOrthogonalDirections) + pathPaintInfo.BridgeImageId + 16; } else diff --git a/src/openrct2/rct12/ScenarioPatcher.cpp b/src/openrct2/rct12/ScenarioPatcher.cpp index 1a52512230..a09185ea97 100644 --- a/src/openrct2/rct12/ScenarioPatcher.cpp +++ b/src/openrct2/rct12/ScenarioPatcher.cpp @@ -655,9 +655,10 @@ static void ApplyPathFixes(const json_t& scenarioPatch) for (auto coordinate : coordinates) { - auto slope = direction != kInvalidDirection ? direction + 4 : 0; + auto slopeType = direction != kInvalidDirection ? FootpathSlopeType::sloped : FootpathSlopeType::flat; auto footpathPlaceAction = GameActions::FootpathPlaceAction( - coordinate.ToCoordsXYZ(), slope, surfaceObjIndex, railingsObjIndex, direction, constructionFlags); + coordinate.ToCoordsXYZ(), { slopeType, direction }, surfaceObjIndex, railingsObjIndex, direction, + constructionFlags); auto& gameState = getGameState(); auto result = footpathPlaceAction.Execute(gameState); if (result.Error != GameActions::Status::Ok) diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 40a26ba13b..5e81770772 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -1196,9 +1196,10 @@ static GameActions::Result TrackDesignPlaceSceneryElement( { flags |= GAME_COMMAND_FLAG_REPLAY; } - uint8_t slope = (scenery.getSlopeDirection() + rotation) & 0x3; + uint8_t slopeDirection = (scenery.getSlopeDirection() + rotation) & 0x3; + FootpathSlope slope = { FootpathSlopeType::flat, slopeDirection }; if (scenery.hasSlope()) - slope |= FOOTPATH_PROPERTIES_FLAG_IS_SLOPED; + slope.type = FootpathSlopeType::sloped; uint8_t edges = Numerics::rol4(scenery.getEdges(), rotation); PathConstructFlags constructFlags = 0; if (scenery.isQueue()) diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 688fb512d5..43f754812d 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -102,23 +102,13 @@ static constexpr uint8_t connected_path_count[] = { }; /** rct2: 0x0098D8B4 */ -static constexpr uint8_t kDefaultPathSlope[] = { - 0, - SLOPE_IS_IRREGULAR_FLAG, - SLOPE_IS_IRREGULAR_FLAG, - FOOTPATH_PROPERTIES_FLAG_IS_SLOPED | 2, - SLOPE_IS_IRREGULAR_FLAG, - SLOPE_IS_IRREGULAR_FLAG, - FOOTPATH_PROPERTIES_FLAG_IS_SLOPED | 3, - RAISE_FOOTPATH_FLAG, - SLOPE_IS_IRREGULAR_FLAG, - FOOTPATH_PROPERTIES_FLAG_IS_SLOPED | 1, - SLOPE_IS_IRREGULAR_FLAG, - RAISE_FOOTPATH_FLAG, - FOOTPATH_PROPERTIES_FLAG_IS_SLOPED | 0, - RAISE_FOOTPATH_FLAG, - RAISE_FOOTPATH_FLAG, - SLOPE_IS_IRREGULAR_FLAG, +static constexpr FootpathSlope kDefaultPathSlope[] = { + { FootpathSlopeType::flat }, { FootpathSlopeType::irregular }, { FootpathSlopeType::irregular }, + { FootpathSlopeType::sloped, 2 }, { FootpathSlopeType::irregular }, { FootpathSlopeType::irregular }, + { FootpathSlopeType::sloped, 3 }, { FootpathSlopeType::raise }, { FootpathSlopeType::irregular }, + { FootpathSlopeType::sloped, 1 }, { FootpathSlopeType::irregular }, { FootpathSlopeType::raise }, + { FootpathSlopeType::sloped, 0 }, { FootpathSlopeType::raise }, { FootpathSlopeType::raise }, + { FootpathSlopeType::irregular }, }; static bool entrance_has_direction(const EntranceElement& entranceElement, int32_t direction) @@ -1923,10 +1913,10 @@ FootpathPlacementResult FootpathGetOnTerrainPlacement(const TileCoordsXY& locati FootpathPlacementResult FootpathGetOnTerrainPlacement(const SurfaceElement& surfaceElement) { int32_t baseZ = surfaceElement.GetBaseZ(); - uint8_t slope = kDefaultPathSlope[surfaceElement.GetSlope() & kTileSlopeRaisedCornersMask]; - if (slope & RAISE_FOOTPATH_FLAG) + auto slope = kDefaultPathSlope[surfaceElement.GetSlope() & kTileSlopeRaisedCornersMask]; + if (slope.type == FootpathSlopeType::raise) { - slope &= ~RAISE_FOOTPATH_FLAG; + slope.type = FootpathSlopeType::flat; baseZ += kPathHeightStep; } diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index 9140d65399..5299c5142d 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -76,10 +76,31 @@ struct FootpathSelection } }; +enum class FootpathSlopeType : uint8_t +{ + flat, + sloped, + /** + * Land has one corner down, raise the Z coordinate and place a flat piece. + */ + raise, + /** + * Terrain has a shape that allows for two different path slopes, and as such it cannot autoplace a piece + * without further context of the surrounding paths. + */ + irregular, +}; + +struct FootpathSlope +{ + FootpathSlopeType type{}; + Direction direction{}; +}; + struct FootpathPlacementResult { int32_t baseZ{}; - uint8_t slope{}; + FootpathSlope slope{}; bool isValid() { diff --git a/src/openrct2/world/tile_element/PathElement.h b/src/openrct2/world/tile_element/PathElement.h index 356b9579d7..236b6295b8 100644 --- a/src/openrct2/world/tile_element/PathElement.h +++ b/src/openrct2/world/tile_element/PathElement.h @@ -32,15 +32,6 @@ namespace OpenRCT2 FOOTPATH_ELEMENT_TYPE_DIRECTION_MASK = (1 << 6) | (1 << 7), }; - // Masks and flags for values stored in TileElement.properties.path.type - enum - { - FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK = (1 << 0) | (1 << 1), - FOOTPATH_PROPERTIES_FLAG_IS_SLOPED = (1 << 2), - FOOTPATH_PROPERTIES_FLAG_HAS_QUEUE_BANNER = (1 << 3), - FOOTPATH_PROPERTIES_TYPE_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7), - }; - // Masks and flags for values stored in TileElement.properties.path.edges enum {