From a6c0c7dd7908c6db229a6c80907e597959afc047 Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Thu, 11 Jan 2024 22:26:06 +0100 Subject: [PATCH 1/2] Move TD6 track flags to RCT12.h --- src/openrct2/rct12/RCT12.h | 19 +++++++++++++++++++ src/openrct2/ride/TrackDesign.h | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index ee48e7a1ca..9ee250e78b 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -169,6 +169,25 @@ enum RCT12_ENTITY_FLAGS_IS_CRASHED_VEHICLE_ENTITY = 1 << 7, }; +// Only written to in RCT2, not used in OpenRCT2. All of these are elements that had to be invented in RCT1. +enum : uint32_t +{ + TRACK_FLAGS_CONTAINS_VERTICAL_LOOP = (1 << 7), + TRACK_FLAGS_CONTAINS_INLINE_TWIST = (1 << 17), + TRACK_FLAGS_CONTAINS_HALF_LOOP = (1 << 18), + TRACK_FLAGS_CONTAINS_CORKSCREW = (1 << 19), + TRACK_FLAGS_CONTAINS_WATER_SPLASH = (1 << 27), + TRACK_FLAGS_CONTAINS_BARREL_ROLL = (1 << 29), + TRACK_FLAGS_CONTAINS_POWERED_LIFT = (1 << 30), + TRACK_FLAGS_CONTAINS_LARGE_HALF_LOOP = (1u << 31), +}; + +enum : uint32_t +{ + TRACK_FLAGS2_CONTAINS_LOG_FLUME_REVERSER = (1 << 1), + TRACK_FLAGS2_SIX_FLAGS_RIDE_DEPRECATED = (1u << 31) // Not used anymore. +}; + #pragma pack(push, 1) struct RCT12xy8 diff --git a/src/openrct2/ride/TrackDesign.h b/src/openrct2/ride/TrackDesign.h index 5325556f19..d9babec962 100644 --- a/src/openrct2/ride/TrackDesign.h +++ b/src/openrct2/ride/TrackDesign.h @@ -177,25 +177,6 @@ private: CoordsXYE MazeGetFirstElement(const Ride& ride); }; -// Only written to in RCT2, not used in OpenRCT2. All of these are elements that had to be invented in RCT1. -enum : uint32_t -{ - TRACK_FLAGS_CONTAINS_VERTICAL_LOOP = (1 << 7), - TRACK_FLAGS_CONTAINS_INLINE_TWIST = (1 << 17), - TRACK_FLAGS_CONTAINS_HALF_LOOP = (1 << 18), - TRACK_FLAGS_CONTAINS_CORKSCREW = (1 << 19), - TRACK_FLAGS_CONTAINS_WATER_SPLASH = (1 << 27), - TRACK_FLAGS_CONTAINS_BARREL_ROLL = (1 << 29), - TRACK_FLAGS_CONTAINS_POWERED_LIFT = (1 << 30), - TRACK_FLAGS_CONTAINS_LARGE_HALF_LOOP = (1u << 31), -}; - -enum : uint32_t -{ - TRACK_FLAGS2_CONTAINS_LOG_FLUME_REVERSER = (1 << 1), - TRACK_FLAGS2_SIX_FLAGS_RIDE_DEPRECATED = (1u << 31) // Not used anymore. -}; - enum { TDPF_PLACE_SCENERY = 1 << 0, From 5593eca03d1e3a48b6fd49592851a4c26911596d Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Thu, 11 Jan 2024 22:27:16 +0100 Subject: [PATCH 2/2] Import maze entrances in the same way as regular ones --- src/openrct2-ui/windows/TrackDesignPlace.cpp | 76 ++-- src/openrct2/rct1/T4Importer.cpp | 7 +- src/openrct2/rct12/RCT12.cpp | 20 + src/openrct2/rct12/RCT12.h | 18 + src/openrct2/rct2/T6Exporter.cpp | 9 + src/openrct2/rct2/T6Importer.cpp | 7 +- src/openrct2/ride/TrackDesign.cpp | 439 ++++++++----------- src/openrct2/ride/TrackDesign.h | 7 - 8 files changed, 263 insertions(+), 320 deletions(-) diff --git a/src/openrct2-ui/windows/TrackDesignPlace.cpp b/src/openrct2-ui/windows/TrackDesignPlace.cpp index dd1dea5027..2c59b97552 100644 --- a/src/openrct2-ui/windows/TrackDesignPlace.cpp +++ b/src/openrct2-ui/windows/TrackDesignPlace.cpp @@ -433,7 +433,40 @@ private: _trackDesign.get(), RideGetTemporaryForPreview(), { loc, z, _currentTrackPieceDirection }); } - void DrawMiniPreviewTrack(TrackDesign* td6, int32_t pass, const CoordsXY& origin, CoordsXY min, CoordsXY max) + void DrawMiniPreviewEntrances( + const TrackDesign& td6, int32_t pass, const CoordsXY& origin, CoordsXY& min, CoordsXY& max, Direction rotation) + { + for (const auto& entrance : td6.entrance_elements) + { + auto rotatedAndOffsetEntrance = origin + entrance.Location.ToCoordsXY().Rotate(rotation); + + if (pass == 0) + { + min.x = std::min(min.x, rotatedAndOffsetEntrance.x); + max.x = std::max(max.x, rotatedAndOffsetEntrance.x); + min.y = std::min(min.y, rotatedAndOffsetEntrance.y); + max.y = std::max(max.y, rotatedAndOffsetEntrance.y); + } + else + { + auto pixelPosition = DrawMiniPreviewGetPixelPosition(rotatedAndOffsetEntrance); + if (DrawMiniPreviewIsPixelInBounds(pixelPosition)) + { + uint8_t* pixel = DrawMiniPreviewGetPixelPtr(pixelPosition); + uint8_t colour = entrance.IsExit ? _PaletteIndexColourExit : _PaletteIndexColourEntrance; + for (int32_t i = 0; i < 4; i++) + { + pixel[338 + i] = colour; // x + 2, y + 2 + pixel[168 + i] = colour; // y + 1 + pixel[2 + i] = colour; // x + 2 + pixel[172 + i] = colour; // x + 4, y + 1 + } + } + } + } + } + + void DrawMiniPreviewTrack(TrackDesign* td6, int32_t pass, const CoordsXY& origin, CoordsXY& min, CoordsXY& max) { const uint8_t rotation = (_currentTrackPieceDirection + GetCurrentRotation()) & 3; @@ -503,38 +536,10 @@ private: } } - // Draw entrance and exit preview. - for (const auto& entrance : td6->entrance_elements) - { - auto rotatedAndOffsetEntrance = origin + entrance.Location.ToCoordsXY().Rotate(rotation); - - if (pass == 0) - { - min.x = std::min(min.x, rotatedAndOffsetEntrance.x); - max.x = std::max(max.x, rotatedAndOffsetEntrance.x); - min.y = std::min(min.y, rotatedAndOffsetEntrance.y); - max.y = std::max(max.y, rotatedAndOffsetEntrance.y); - } - else - { - auto pixelPosition = DrawMiniPreviewGetPixelPosition(rotatedAndOffsetEntrance); - if (DrawMiniPreviewIsPixelInBounds(pixelPosition)) - { - uint8_t* pixel = DrawMiniPreviewGetPixelPtr(pixelPosition); - uint8_t colour = entrance.IsExit ? _PaletteIndexColourExit : _PaletteIndexColourEntrance; - for (int32_t i = 0; i < 4; i++) - { - pixel[338 + i] = colour; // x + 2, y + 2 - pixel[168 + i] = colour; // y + 1 - pixel[2 + i] = colour; // x + 2 - pixel[172 + i] = colour; // x + 4, y + 1 - } - } - } - } + DrawMiniPreviewEntrances(*td6, pass, origin, min, max, rotation); } - void DrawMiniPreviewMaze(TrackDesign* td6, int32_t pass, const CoordsXY& origin, CoordsXY min, CoordsXY max) + void DrawMiniPreviewMaze(TrackDesign* td6, int32_t pass, const CoordsXY& origin, CoordsXY& min, CoordsXY& max) { uint8_t rotation = (_currentTrackPieceDirection + GetCurrentRotation()) & 3; for (const auto& mazeElement : td6->maze_elements) @@ -556,13 +561,6 @@ private: uint8_t* pixel = DrawMiniPreviewGetPixelPtr(pixelPosition); uint8_t colour = _PaletteIndexColourTrack; - - // Draw entrance and exit with different colours. - if (mazeElement.type == MAZE_ELEMENT_TYPE_ENTRANCE) - colour = _PaletteIndexColourEntrance; - else if (mazeElement.type == MAZE_ELEMENT_TYPE_EXIT) - colour = _PaletteIndexColourExit; - for (int32_t i = 0; i < 4; i++) { pixel[338 + i] = colour; // x + 2, y + 2 @@ -573,6 +571,8 @@ private: } } } + + DrawMiniPreviewEntrances(*td6, pass, origin, min, max, rotation); } ScreenCoordsXY DrawMiniPreviewGetPixelPosition(const CoordsXY& location) diff --git a/src/openrct2/rct1/T4Importer.cpp b/src/openrct2/rct1/T4Importer.cpp index bcf2444c58..89eaff9dbc 100644 --- a/src/openrct2/rct1/T4Importer.cpp +++ b/src/openrct2/rct1/T4Importer.cpp @@ -250,12 +250,7 @@ namespace RCT1 _stream.Read(&t4MazeElement, sizeof(TD46MazeElement)); if (t4MazeElement.All != 0) { - TrackDesignMazeElement mazeElement{}; - mazeElement.x = t4MazeElement.x; - mazeElement.y = t4MazeElement.y; - mazeElement.direction = t4MazeElement.Direction; - mazeElement.type = t4MazeElement.Type; - td->maze_elements.push_back(mazeElement); + ImportMazeElement(*td, t4MazeElement); } } } diff --git a/src/openrct2/rct12/RCT12.cpp b/src/openrct2/rct12/RCT12.cpp index 1fda91e466..1eee342ce3 100644 --- a/src/openrct2/rct12/RCT12.cpp +++ b/src/openrct2/rct12/RCT12.cpp @@ -925,6 +925,26 @@ uint8_t ConvertToTD46Flags(const TrackDesignTrackElement& source) return trackFlags; } +void ImportMazeElement(TrackDesign& td, const TD46MazeElement& td46MazeElement) +{ + if (td46MazeElement.IsEntrance() || td46MazeElement.IsExit()) + { + TrackDesignEntranceElement element{}; + element.Location = TileCoordsXYZD(td46MazeElement.x, td46MazeElement.y, 0, td46MazeElement.Direction); + element.IsExit = td46MazeElement.IsExit(); + td.entrance_elements.push_back(element); + } + else + { + TrackDesignMazeElement mazeElement{}; + mazeElement.x = td46MazeElement.x; + mazeElement.y = td46MazeElement.y; + mazeElement.direction = td46MazeElement.Direction; + mazeElement.type = td46MazeElement.Type; + td.maze_elements.push_back(mazeElement); + } +} + namespace RCT12 { size_t GetRCTStringBufferLen(const char* buffer, size_t maxBufferLen) diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index 9ee250e78b..c01bf76ced 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -74,6 +74,7 @@ constexpr uint8_t RCT12PeepThoughtItemNone = std::numeric_limits::max() constexpr uint8_t RCT12GuestsInParkHistoryFactor = 20; constexpr uint8_t RCT12ParkHistoryUndefined = std::numeric_limits::max(); +struct TrackDesign; struct TrackDesignTrackElement; enum class RCT12TrackDesignVersion : uint8_t @@ -213,6 +214,12 @@ struct RCT12xy8 }; assert_struct_size(RCT12xy8, 2); +enum class TD46MazeElementType : uint8_t +{ + Entrance = (1 << 3), + Exit = (1 << 7) +}; + /* Maze Element entry size: 0x04 */ struct TD46MazeElement { @@ -234,6 +241,16 @@ struct TD46MazeElement }; }; }; + + constexpr bool IsEntrance() const + { + return Type == EnumValue(TD46MazeElementType::Entrance); + } + + constexpr bool IsExit() const + { + return Type == EnumValue(TD46MazeElementType::Exit); + } }; assert_struct_size(TD46MazeElement, 0x04); @@ -933,6 +950,7 @@ enum class TD46Flags : uint8_t void ConvertFromTD46Flags(TrackDesignTrackElement& target, uint8_t flags); uint8_t ConvertToTD46Flags(const TrackDesignTrackElement& source); +void ImportMazeElement(TrackDesign& td, const TD46MazeElement& td46MazeElement); namespace RCT12 { diff --git a/src/openrct2/rct2/T6Exporter.cpp b/src/openrct2/rct2/T6Exporter.cpp index b8ce5ea85b..22aad186ff 100644 --- a/src/openrct2/rct2/T6Exporter.cpp +++ b/src/openrct2/rct2/T6Exporter.cpp @@ -107,6 +107,15 @@ namespace RCT2 tempStream.WriteValue(mazeElement.all); } + for (const auto& entranceElement : _trackDesign->entrance_elements) + { + tempStream.WriteValue(entranceElement.Location.x); + tempStream.WriteValue(entranceElement.Location.y); + tempStream.WriteValue(entranceElement.Location.direction); + tempStream.WriteValue( + EnumValue(entranceElement.IsExit ? TD46MazeElementType::Exit : TD46MazeElementType::Entrance)); + } + tempStream.WriteValue(0); } else diff --git a/src/openrct2/rct2/T6Importer.cpp b/src/openrct2/rct2/T6Importer.cpp index 8346b5f44b..9483eaea04 100644 --- a/src/openrct2/rct2/T6Importer.cpp +++ b/src/openrct2/rct2/T6Importer.cpp @@ -148,12 +148,7 @@ namespace RCT2 _stream.Read(&t6MazeElement, sizeof(TD46MazeElement)); if (t6MazeElement.All != 0) { - TrackDesignMazeElement mazeElement{}; - mazeElement.x = t6MazeElement.x; - mazeElement.y = t6MazeElement.y; - mazeElement.direction = t6MazeElement.Direction; - mazeElement.type = t6MazeElement.Type; - td->maze_elements.push_back(mazeElement); + ImportMazeElement(*td, t6MazeElement); } } } diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 54917b1b04..17ce50c916 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -412,13 +412,11 @@ ResultWithMessage TrackDesign::CreateTrackDesignMaze(TrackDesignState& tds, cons } while (!(tileElement++)->IsLastForTile()); // Add something that stops this from walking off the end - uint8_t entranceDirection = tileElement->GetDirection(); - TrackDesignMazeElement mazeEntrance{}; - mazeEntrance.direction = entranceDirection; - mazeEntrance.type = 8; - mazeEntrance.x = static_cast((entranceLoc.x - startLoc.x) / 32); - mazeEntrance.y = static_cast((entranceLoc.y - startLoc.y) / 32); - maze_elements.push_back(mazeEntrance); + auto entranceOffset = entranceLoc - startLoc; + TrackDesignEntranceElement mazeEntrance{}; + mazeEntrance.Location = TileCoordsXYZD(CoordsXYZD(entranceOffset, 0, tileElement->GetDirection())); + mazeEntrance.IsExit = false; + entrance_elements.push_back(mazeEntrance); location = ride.GetStation().Exit; if (location.IsNull()) @@ -441,13 +439,11 @@ ResultWithMessage TrackDesign::CreateTrackDesignMaze(TrackDesignState& tds, cons } while (!(tileElement++)->IsLastForTile()); // Add something that stops this from walking off the end - uint8_t exit_direction = tileElement->GetDirection(); - TrackDesignMazeElement mazeExit{}; - mazeExit.direction = exit_direction; - mazeExit.type = 0x80; - mazeExit.x = static_cast((exitLoc.x - startLoc.x) / 32); - mazeExit.y = static_cast((exitLoc.y - startLoc.y) / 32); - maze_elements.push_back(mazeExit); + auto exitOffset = exitLoc - startLoc; + TrackDesignEntranceElement mazeExit{}; + mazeExit.Location = TileCoordsXYZD(CoordsXYZD(exitOffset, 0, tileElement->GetDirection())); + mazeExit.IsExit = true; + entrance_elements.push_back(mazeExit); // Save global vars as they are still used by scenery???? int32_t startZ = tds.Origin.z; @@ -874,6 +870,18 @@ static void TrackDesignMirrorScenery(TrackDesign* td6) } } +static void TrackDesignMirrorEntrances(TrackDesign& td) +{ + for (auto& entrance : td.entrance_elements) + { + entrance.Location.y = -entrance.Location.y; + if (entrance.Location.direction & 1) + { + entrance.Location.direction = DirectionReverse(entrance.Location.direction); + } + } +} + /** * * rct2: 0x006D2443 @@ -885,15 +893,6 @@ static void TrackDesignMirrorRide(TrackDesign* td6) const auto& ted = GetTrackElementDescriptor(track.Type); track.Type = ted.MirrorElement; } - - for (auto& entrance : td6->entrance_elements) - { - entrance.Location.y = -entrance.Location.y; - if (entrance.Location.direction & 1) - { - entrance.Location.direction = DirectionReverse(entrance.Location.direction); - } - } } /** rct2: 0x00993EDC */ @@ -911,15 +910,6 @@ static void TrackDesignMirrorMaze(TrackDesign* td6) { maze.y = -maze.y; - if (maze.type == 0x8 || maze.type == 0x80) - { - if (maze.direction & 1) - { - maze.direction = DirectionReverse(maze.direction); - } - continue; - } - uint16_t maze_entry = maze.maze_entry; uint16_t new_entry = 0; for (uint8_t position = UtilBitScanForward(maze_entry); position != 0xFF; position = UtilBitScanForward(maze_entry)) @@ -946,6 +936,7 @@ void TrackDesignMirror(TrackDesign* td6) { TrackDesignMirrorRide(td6); } + TrackDesignMirrorEntrances(*td6); TrackDesignMirrorScenery(td6); } @@ -1347,27 +1338,130 @@ static GameActions::Result TrackDesignPlaceAllScenery( return res; } +static std::optional TrackDesignPlaceEntrances( + TrackDesignState& tds, const TrackDesign& td, CoordsXYZ newCoords, RideId rideId, money64& totalCost) +{ + for (const auto& entrance : td.entrance_elements) + { + auto rotation = _currentTrackPieceDirection & 3; + CoordsXY entranceMapPos = entrance.Location.ToCoordsXY(); + auto rotatedEntranceMapPos = entranceMapPos.Rotate(rotation); + newCoords = { rotatedEntranceMapPos + tds.Origin, newCoords.z }; + + TrackDesignUpdatePreviewBounds(tds, newCoords); + + switch (tds.PlaceOperation) + { + case PTD_OPERATION_DRAW_OUTLINES: + TrackDesignAddSelectedTile(newCoords); + break; + case PTD_OPERATION_PLACE_QUERY: + case PTD_OPERATION_PLACE: + case PTD_OPERATION_PLACE_GHOST: + case PTD_OPERATION_PLACE_TRACK_PREVIEW: + { + rotation = (rotation + entrance.Location.direction) & 3; + newCoords.z = entrance.Location.z * COORDS_Z_STEP; + newCoords.z += tds.Origin.z; + + if (tds.PlaceOperation != PTD_OPERATION_PLACE_QUERY) + { + auto tile = CoordsXY{ newCoords } + CoordsDirectionDelta[rotation]; + TileElement* tile_element = MapGetFirstElementAt(tile); + if (tile_element == nullptr) + { + return GameActions::Result(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); + } + + do + { + if (tile_element->GetType() != TileElementType::Track) + { + continue; + } + if (tile_element->GetBaseZ() != newCoords.z) + { + continue; + } + + auto stationIndex = tile_element->AsTrack()->GetStationIndex(); + uint8_t flags = GAME_COMMAND_FLAG_APPLY; + if (tds.PlaceOperation == PTD_OPERATION_PLACE_TRACK_PREVIEW) + { + flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED + | GAME_COMMAND_FLAG_NO_SPEND; + } + if (tds.PlaceOperation == PTD_OPERATION_PLACE_GHOST) + { + flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND + | GAME_COMMAND_FLAG_GHOST; + } + if (tds.PlaceOperation == PTD_OPERATION_PLACE_QUERY) + { + flags = 0; + } + if (tds.IsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } + + auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction( + newCoords, rotation, rideId, stationIndex, entrance.IsExit); + rideEntranceExitPlaceAction.SetFlags(flags); + auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&rideEntranceExitPlaceAction) + : GameActions::QueryNested(&rideEntranceExitPlaceAction); + + if (res.Error != GameActions::Status::Ok) + { + return res; + } + totalCost += res.Cost; + tds.EntranceExitPlaced = true; + _trackDesignPlaceStateEntranceExitPlaced = true; + break; + } while (!(tile_element++)->IsLastForTile()); + } + else + { + auto res = RideEntranceExitPlaceAction::TrackPlaceQuery(newCoords, false); + if (res.Error != GameActions::Status::Ok) + { + return GameActions::Result(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); + } + + totalCost += res.Cost; + tds.EntranceExitPlaced = true; + _trackDesignPlaceStateEntranceExitPlaced = true; + } + break; + } + } + } + + return std::nullopt; +} + static GameActions::Result TrackDesignPlaceMaze( - TrackDesignState& tds, TrackDesign* td6, const CoordsXYZ& coords, const Ride& ride) + TrackDesignState& tds, TrackDesign& td, const CoordsXYZ& origin, const Ride& ride) { if (tds.PlaceOperation == PTD_OPERATION_DRAW_OUTLINES) { gMapSelectionTiles.clear(); - gMapSelectArrowPosition = CoordsXYZ{ coords, TileElementHeight(coords) }; + gMapSelectArrowPosition = CoordsXYZ{ origin, TileElementHeight(origin) }; gMapSelectArrowDirection = _currentTrackPieceDirection; } tds.PlaceZ = 0; money64 totalCost = 0; - for (const auto& maze_element : td6->maze_elements) + for (const auto& maze_element : td.maze_elements) { uint8_t rotation = _currentTrackPieceDirection & 3; CoordsXY mazeMapPos = TileCoordsXY(maze_element.x, maze_element.y).ToCoordsXY(); auto mapCoord = mazeMapPos.Rotate(rotation); - mapCoord += coords; + mapCoord += origin; - TrackDesignUpdatePreviewBounds(tds, { mapCoord, coords.z }); + TrackDesignUpdatePreviewBounds(tds, { mapCoord, origin.z }); if (tds.PlaceOperation == PTD_OPERATION_DRAW_OUTLINES) { @@ -1379,135 +1473,40 @@ static GameActions::Result TrackDesignPlaceMaze( { uint8_t flags; money64 cost = 0; - uint16_t maze_entry; - switch (maze_element.type) + + uint16_t maze_entry = Numerics::rol16(maze_element.maze_entry, rotation * 4); + + if (tds.PlaceOperation == PTD_OPERATION_PLACE_TRACK_PREVIEW) { - case MAZE_ELEMENT_TYPE_ENTRANCE: - // entrance - rotation += maze_element.direction; - rotation &= 3; - - flags = GAME_COMMAND_FLAG_APPLY; - - if (tds.PlaceOperation == PTD_OPERATION_PLACE_QUERY) - { - auto res = RideEntranceExitPlaceAction::TrackPlaceQuery({ mapCoord, coords.z }, false); - if (res.Error != GameActions::Status::Ok) - { - return res; - } - cost = res.Cost; - } - else - { - if (tds.PlaceOperation == PTD_OPERATION_PLACE_TRACK_PREVIEW) - { - flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED - | GAME_COMMAND_FLAG_NO_SPEND; - } - else if (tds.PlaceOperation == PTD_OPERATION_PLACE_GHOST) - { - flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND - | GAME_COMMAND_FLAG_GHOST; - } - if (tds.IsReplay) - { - flags |= GAME_COMMAND_FLAG_REPLAY; - } - auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction( - mapCoord, rotation, ride.id, StationIndex::FromUnderlying(0), false); - rideEntranceExitPlaceAction.SetFlags(flags); - auto res = GameActions::ExecuteNested(&rideEntranceExitPlaceAction); - if (res.Error != GameActions::Status::Ok) - { - return res; - } - cost = res.Cost; - } - tds.EntranceExitPlaced = true; - _trackDesignPlaceStateEntranceExitPlaced = true; - break; - case MAZE_ELEMENT_TYPE_EXIT: - // exit - rotation += maze_element.direction; - rotation &= 3; - - flags = GAME_COMMAND_FLAG_APPLY; - - if (tds.PlaceOperation == PTD_OPERATION_PLACE_QUERY) - { - auto res = RideEntranceExitPlaceAction::TrackPlaceQuery({ mapCoord, coords.z }, true); - if (res.Error != GameActions::Status::Ok) - { - return res; - } - cost = res.Cost; - } - else - { - if (tds.PlaceOperation == PTD_OPERATION_PLACE_TRACK_PREVIEW) - { - flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED - | GAME_COMMAND_FLAG_NO_SPEND; - } - else if (tds.PlaceOperation == PTD_OPERATION_PLACE_GHOST) - { - flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND - | GAME_COMMAND_FLAG_GHOST; - } - if (tds.IsReplay) - { - flags |= GAME_COMMAND_FLAG_REPLAY; - } - auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction( - mapCoord, rotation, ride.id, StationIndex::FromUnderlying(0), true); - rideEntranceExitPlaceAction.SetFlags(flags); - auto res = GameActions::ExecuteNested(&rideEntranceExitPlaceAction); - if (res.Error != GameActions::Status::Ok) - { - return res; - } - cost = res.Cost; - } - tds.EntranceExitPlaced = true; - _trackDesignPlaceStateEntranceExitPlaced = true; - break; - default: - maze_entry = Numerics::rol16(maze_element.maze_entry, rotation * 4); - - if (tds.PlaceOperation == PTD_OPERATION_PLACE_TRACK_PREVIEW) - { - flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND; - } - else if (tds.PlaceOperation == PTD_OPERATION_PLACE_GHOST) - { - flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND - | GAME_COMMAND_FLAG_GHOST; - } - else if (tds.PlaceOperation == PTD_OPERATION_PLACE_QUERY) - { - flags = 0; - } - else - { - flags = GAME_COMMAND_FLAG_APPLY; - } - if (tds.IsReplay) - { - flags |= GAME_COMMAND_FLAG_REPLAY; - } - - auto mazePlace = MazePlaceTrackAction({ mapCoord, coords.z }, ride.id, maze_entry); - mazePlace.SetFlags(flags); - auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&mazePlace) - : GameActions::QueryNested(&mazePlace); - if (res.Error != GameActions::Status::Ok) - { - return res; - } - cost = res.Cost; - break; + flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND; } + else if (tds.PlaceOperation == PTD_OPERATION_PLACE_GHOST) + { + flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND + | GAME_COMMAND_FLAG_GHOST; + } + else if (tds.PlaceOperation == PTD_OPERATION_PLACE_QUERY) + { + flags = 0; + } + else + { + flags = GAME_COMMAND_FLAG_APPLY; + } + if (tds.IsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } + + auto mazePlace = MazePlaceTrackAction({ mapCoord, origin.z }, ride.id, maze_entry); + mazePlace.SetFlags(flags); + auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&mazePlace) + : GameActions::QueryNested(&mazePlace); + if (res.Error != GameActions::Status::Ok) + { + return res; + } + cost = res.Cost; totalCost += cost; } @@ -1538,7 +1537,7 @@ static GameActions::Result TrackDesignPlaceMaze( surfaceZ = waterZ; } - int16_t temp_z = coords.z + tds.PlaceZ - surfaceZ; + int16_t temp_z = origin.z + tds.PlaceZ - surfaceZ; if (temp_z < 0) { tds.PlaceZ -= temp_z; @@ -1546,6 +1545,14 @@ static GameActions::Result TrackDesignPlaceMaze( } } + tds.Origin = origin; + + auto result = TrackDesignPlaceEntrances(tds, td, origin, ride.id, totalCost); + if (result.has_value()) + { + return result.value(); + } + if (tds.PlaceOperation == PTD_OPERATION_REMOVE_GHOST) { auto gameAction = RideDemolishAction(ride.id, RIDE_MODIFY_DEMOLISH); @@ -1553,8 +1560,6 @@ static GameActions::Result TrackDesignPlaceMaze( GameActions::Execute(&gameAction); } - tds.Origin = coords; - auto res = GameActions::Result(); res.Cost = totalCost; @@ -1721,102 +1726,10 @@ static GameActions::Result TrackDesignPlaceRide(TrackDesignState& tds, TrackDesi } } - // Entrance elements - for (const auto& entrance : td6->entrance_elements) + auto result = TrackDesignPlaceEntrances(tds, *td6, newCoords, ride.id, totalCost); + if (result.has_value()) { - rotation = _currentTrackPieceDirection & 3; - CoordsXY entranceMapPos = entrance.Location.ToCoordsXY(); - auto rotatedEntranceMapPos = entranceMapPos.Rotate(rotation); - newCoords = { rotatedEntranceMapPos + tds.Origin, newCoords.z }; - - TrackDesignUpdatePreviewBounds(tds, newCoords); - - switch (tds.PlaceOperation) - { - case PTD_OPERATION_DRAW_OUTLINES: - TrackDesignAddSelectedTile(newCoords); - break; - case PTD_OPERATION_PLACE_QUERY: - case PTD_OPERATION_PLACE: - case PTD_OPERATION_PLACE_GHOST: - case PTD_OPERATION_PLACE_TRACK_PREVIEW: - { - rotation = (rotation + entrance.Location.direction) & 3; - newCoords.z = entrance.Location.z * COORDS_Z_STEP; - newCoords.z += tds.Origin.z; - - if (tds.PlaceOperation != PTD_OPERATION_PLACE_QUERY) - { - auto tile = CoordsXY{ newCoords } + CoordsDirectionDelta[rotation]; - TileElement* tile_element = MapGetFirstElementAt(tile); - if (tile_element == nullptr) - { - return GameActions::Result(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); - } - - do - { - if (tile_element->GetType() != TileElementType::Track) - { - continue; - } - if (tile_element->GetBaseZ() != newCoords.z) - { - continue; - } - - auto stationIndex = tile_element->AsTrack()->GetStationIndex(); - uint8_t flags = GAME_COMMAND_FLAG_APPLY; - if (tds.PlaceOperation == PTD_OPERATION_PLACE_TRACK_PREVIEW) - { - flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED - | GAME_COMMAND_FLAG_NO_SPEND; - } - if (tds.PlaceOperation == PTD_OPERATION_PLACE_GHOST) - { - flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND - | GAME_COMMAND_FLAG_GHOST; - } - if (tds.PlaceOperation == PTD_OPERATION_PLACE_QUERY) - { - flags = 0; - } - if (tds.IsReplay) - { - flags |= GAME_COMMAND_FLAG_REPLAY; - } - - auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction( - newCoords, rotation, ride.id, stationIndex, entrance.IsExit); - rideEntranceExitPlaceAction.SetFlags(flags); - auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&rideEntranceExitPlaceAction) - : GameActions::QueryNested(&rideEntranceExitPlaceAction); - - if (res.Error != GameActions::Status::Ok) - { - return res; - } - totalCost += res.Cost; - tds.EntranceExitPlaced = true; - _trackDesignPlaceStateEntranceExitPlaced = true; - break; - } while (!(tile_element++)->IsLastForTile()); - } - else - { - auto res = RideEntranceExitPlaceAction::TrackPlaceQuery(newCoords, false); - if (res.Error != GameActions::Status::Ok) - { - return GameActions::Result(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); - } - - totalCost += res.Cost; - tds.EntranceExitPlaced = true; - _trackDesignPlaceStateEntranceExitPlaced = true; - } - break; - } - } + return result.value(); } if (tds.PlaceOperation == PTD_OPERATION_REMOVE_GHOST) @@ -1877,7 +1790,7 @@ static GameActions::Result TrackDesignPlaceVirtual( const auto& rtd = GetRideTypeDescriptor(td6->type); if (rtd.HasFlag(RIDE_TYPE_FLAG_IS_MAZE)) { - trackPlaceRes = TrackDesignPlaceMaze(tds, td6, coords, ride); + trackPlaceRes = TrackDesignPlaceMaze(tds, *td6, coords, ride); } else { diff --git a/src/openrct2/ride/TrackDesign.h b/src/openrct2/ride/TrackDesign.h index d9babec962..800d4904eb 100644 --- a/src/openrct2/ride/TrackDesign.h +++ b/src/openrct2/ride/TrackDesign.h @@ -202,13 +202,6 @@ enum static constexpr uint8_t PTD_OPERATION_FLAG_IS_REPLAY = (1 << 7); -enum -{ - MAZE_ELEMENT_TYPE_MAZE_TRACK = 0, - MAZE_ELEMENT_TYPE_ENTRANCE = (1 << 3), - MAZE_ELEMENT_TYPE_EXIT = (1 << 7) -}; - extern bool gTrackDesignSceneryToggle; extern bool _trackDesignDrawingPreview;