From de7051d9403c65e8f15ac18e696a893a3df200bd Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Sun, 5 Apr 2020 08:28:07 +0100 Subject: [PATCH] Fix #11225: Track design replays. The replay state was not being passed to all sub actions this prevented the replay from working. Note replays made before this still work its just they couldn't be replayed. name the flag Update changelog --- distribution/changelog.txt | 1 + src/openrct2/actions/TrackDesignAction.cpp | 5 +- src/openrct2/ride/TrackDesign.cpp | 55 ++++++++++++++++++---- src/openrct2/ride/TrackDesign.h | 2 + 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index cb9e7a68bf..3e7b876559 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -13,6 +13,7 @@ - Fix: [#11126] Cannot place Frightmare track design. - Fix: [#11208] Cannot export parks with RCT2 DLC objects. - Fix: [#11230] Seat Rotation not imported correctly for hacked rides. +- Fix: [#11225] Replay manager cannot handle track designs. - Fix: Small red gardens in RCT1 saves are imported in the wrong colour. - Improved: [#11157] Slimmer virtual floor lines. diff --git a/src/openrct2/actions/TrackDesignAction.cpp b/src/openrct2/actions/TrackDesignAction.cpp index 9d1b3c9d7a..f3707ed59e 100644 --- a/src/openrct2/actions/TrackDesignAction.cpp +++ b/src/openrct2/actions/TrackDesignAction.cpp @@ -211,7 +211,10 @@ GameActionResult::Ptr TrackDesignAction::Execute() const { operation = PTD_OPERATION_PLACE; } - + if (GetFlags() & GAME_COMMAND_FLAG_REPLAY) + { + operation |= PTD_OPERATION_FLAG_IS_REPLAY; + } cost = place_virtual_track(_td, operation, placeScenery, ride, _loc); } diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index a00fec9c70..c01cdfca7a 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -91,6 +91,7 @@ static bool _trackDesignPlaceStateEntranceExitPlaced = false; bool _trackDesignPlaceStateSceneryUnavailable = false; static bool _trackDesignPlaceStateHasScenery = false; static bool _trackDesignPlaceStatePlaceScenery = true; +static bool _trackDesignPlaceIsReplay = false; static map_backup* track_design_preview_backup_map(); @@ -1036,7 +1037,10 @@ static bool TrackDesignPlaceSceneryElement( { flags = GAME_COMMAND_FLAG_PATH_SCENERY; } - + if (_trackDesignPlaceIsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } gGameCommandErrorTitle = STR_CANT_POSITION_THIS_HERE; auto smallSceneryPlace = SmallSceneryPlaceAction( @@ -1081,12 +1085,15 @@ static bool TrackDesignPlaceSceneryElement( { flags = GAME_COMMAND_FLAG_PATH_SCENERY; } - + if (_trackDesignPlaceIsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } auto sceneryPlaceAction = LargeSceneryPlaceAction( { mapCoord.x, mapCoord.y, z, rotation }, entry_index, scenery.primary_colour, scenery.secondary_colour); sceneryPlaceAction.SetFlags(flags); - auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::Execute(&sceneryPlaceAction) - : GameActions::Query(&sceneryPlaceAction); + auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&sceneryPlaceAction) + : GameActions::QueryNested(&sceneryPlaceAction); cost = res->Cost; break; @@ -1121,7 +1128,10 @@ static bool TrackDesignPlaceSceneryElement( { flags = 0; } - + if (_trackDesignPlaceIsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } auto wallPlaceAction = WallPlaceAction( entry_index, { mapCoord.x, mapCoord.y, z }, rotation, scenery.primary_colour, scenery.secondary_colour, (scenery.flags & 0xFC) >> 2); @@ -1169,7 +1179,10 @@ static bool TrackDesignPlaceSceneryElement( { flags = 0; } - + if (_trackDesignPlaceIsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } uint8_t slope = ((bh >> 5) & 0x3) | ((bh >> 2) & 0x4); uint8_t edges = bh & 0xF; auto footpathPlaceAction = FootpathPlaceFromTrackAction( @@ -1207,7 +1220,10 @@ static bool TrackDesignPlaceSceneryElement( flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST; } - + if (_trackDesignPlaceIsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } footpath_connect_edges(mapCoord, reinterpret_cast(pathElement), flags); footpath_update_queue_chains(); return true; @@ -1337,6 +1353,10 @@ static int32_t track_design_place_maze(TrackDesign* td6, int16_t x, int16_t y, i flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST; } + if (_trackDesignPlaceIsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction(mapCoord, rotation, ride->id, 0, false); rideEntranceExitPlaceAction.SetFlags(flags); auto res = GameActions::ExecuteNested(&rideEntranceExitPlaceAction); @@ -1372,6 +1392,10 @@ static int32_t track_design_place_maze(TrackDesign* td6, int16_t x, int16_t y, i flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST; } + if (_trackDesignPlaceIsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction(mapCoord, rotation, ride->id, 0, true); rideEntranceExitPlaceAction.SetFlags(flags); auto res = GameActions::ExecuteNested(&rideEntranceExitPlaceAction); @@ -1402,7 +1426,10 @@ static int32_t track_design_place_maze(TrackDesign* td6, int16_t x, int16_t y, i { flags = GAME_COMMAND_FLAG_APPLY; } - + if (_trackDesignPlaceIsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } gGameCommandErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; auto mazePlace = MazePlaceTrackAction({ mapCoord, z }, ride->id, maze_entry); @@ -1560,7 +1587,10 @@ static bool track_design_place_ride(TrackDesign* td6, int16_t x, int16_t y, int1 { flags = 0; } - + if (_trackDesignPlaceIsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } gGameCommandErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; auto trackPlaceAction = TrackPlaceAction( _currentRideIndex, trackType, { x, y, tempZ, static_cast(rotation) }, brakeSpeed, trackColour, @@ -1701,7 +1731,10 @@ static bool track_design_place_ride(TrackDesign* td6, int16_t x, int16_t y, int1 { flags = 0; } - + if (_trackDesignPlaceIsReplay) + { + flags |= GAME_COMMAND_FLAG_REPLAY; + } gGameCommandErrorTitle = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; auto rideEntranceExitPlaceAction = RideEntranceExitPlaceAction( { x, y }, rotation, ride->id, stationIndex, entrance.isExit); @@ -1772,6 +1805,8 @@ int32_t place_virtual_track( _trackDesignPlaceStateSceneryUnavailable = false; _trackDesignPlaceStateHasScenery = false; + _trackDesignPlaceIsReplay = ptdOperation & PTD_OPERATION_FLAG_IS_REPLAY; + ptdOperation &= ~PTD_OPERATION_FLAG_IS_REPLAY; _trackDesignPlaceOperation = ptdOperation; if (gTrackDesignSceneryToggle) { diff --git a/src/openrct2/ride/TrackDesign.h b/src/openrct2/ride/TrackDesign.h index 5947e57358..3b05beb61b 100644 --- a/src/openrct2/ride/TrackDesign.h +++ b/src/openrct2/ride/TrackDesign.h @@ -183,6 +183,8 @@ enum PTD_OPERATION_REMOVE_GHOST, }; +static constexpr uint8_t PTD_OPERATION_FLAG_IS_REPLAY = (1 << 7); + enum { MAZE_ELEMENT_TYPE_MAZE_TRACK = 0,