diff --git a/distribution/changelog.txt b/distribution/changelog.txt index dbe17103cc..39fa549daa 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -30,8 +30,9 @@ - Fix: [#15255] Tile Inspector shows banner information on walls that do not contain one. - Fix: [#15257] Chat icon shows in scenario/track editor. Other icons don't disable when deactivated in options menu. - Fix: [#15289] Unexpected behavior with duplicated banners which also caused desyncs in multiplayer. -- Fix: [#15451] Guest list name filter remains after group selection. +- Fix: [#15322] Circus music doesn't play. - Fix: [#15377] Entrance/exit ghost doesn't work on different stations without touching them first. +- Fix: [#15451] Guest list name filter remains after group selection. - Fix: [#15476] Crash when placing/clearing small scenery. - Fix: [#15487] Map animations do not work correctly when loading an exported SV6 file in vanilla RCT2. - Fix: [#15490] Tile inspector needlessly updates clearance height when changing surface slopes. diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index b34917ff6d..d582e02a56 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -1664,8 +1664,8 @@ static void window_ride_construction_dropdown(rct_window* w, rct_widgetindex wid _currentTrackCurve = trackPiece | RideConstructionSpecialPieceSelected; window_ride_construction_update_active_elements(); } -static void RideConstructPlacedForwardGameActionCallback(const GameAction* ga, const TrackPlaceActionResult* result); -static void RideConstructPlacedBackwardGameActionCallback(const GameAction* ga, const TrackPlaceActionResult* result); +static void RideConstructPlacedForwardGameActionCallback(const GameAction* ga, const GameActions::Result* result); +static void RideConstructPlacedBackwardGameActionCallback(const GameAction* ga, const GameActions::Result* result); static void CloseConstructWindowOnCompletion(Ride* ride); static void CloseConstructWindowOnCompletion(Ride* ride) @@ -1687,7 +1687,7 @@ static void CloseConstructWindowOnCompletion(Ride* ride) } } -static void RideConstructPlacedForwardGameActionCallback(const GameAction* ga, const TrackPlaceActionResult* result) +static void RideConstructPlacedForwardGameActionCallback(const GameAction* ga, const GameActions::Result* result) { if (result->Error != GameActions::Status::Ok) { @@ -1732,7 +1732,7 @@ static void RideConstructPlacedForwardGameActionCallback(const GameAction* ga, c CloseConstructWindowOnCompletion(ride); } -static void RideConstructPlacedBackwardGameActionCallback(const GameAction* ga, const TrackPlaceActionResult* result) +static void RideConstructPlacedBackwardGameActionCallback(const GameAction* ga, const GameActions::Result* result) { if (result->Error != GameActions::Status::Ok) { @@ -1833,8 +1833,8 @@ static void window_ride_construction_construct(rct_window* w) _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_TRACK_PLACE_ACTION_QUEUED; } - auto tpar = dynamic_cast(res.get()); - if (tpar != nullptr && tpar->GroundFlags & ELEMENT_IS_UNDERGROUND) + const auto resultData = res->GetData(); + if (resultData.GroundFlags & ELEMENT_IS_UNDERGROUND) { viewport_set_visibility(1); } diff --git a/src/openrct2-ui/windows/TrackDesignPlace.cpp b/src/openrct2-ui/windows/TrackDesignPlace.cpp index 44397b4ceb..24943c1148 100644 --- a/src/openrct2-ui/windows/TrackDesignPlace.cpp +++ b/src/openrct2-ui/windows/TrackDesignPlace.cpp @@ -289,10 +289,10 @@ static void window_track_place_toolupdate(rct_window* w, rct_widgetindex widgetI // Valid location found. Place the ghost at the location. auto tdAction = TrackDesignAction({ trackLoc, _currentTrackPieceDirection }, *_trackDesign); tdAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST); - tdAction.SetCallback([trackLoc](const GameAction*, const TrackDesignActionResult* result) { + tdAction.SetCallback([trackLoc](const GameAction*, const GameActions::Result* result) { if (result->Error == GameActions::Status::Ok) { - _window_track_place_ride_index = result->rideIndex; + _window_track_place_ride_index = result->GetData(); _windowTrackPlaceLastValid = trackLoc; _window_track_place_last_was_valid = true; } @@ -336,20 +336,21 @@ static void window_track_place_tooldown(rct_window* w, rct_widgetindex widgetInd if (res->Error == GameActions::Status::Ok) { auto tdAction = TrackDesignAction({ trackLoc, _currentTrackPieceDirection }, *_trackDesign); - tdAction.SetCallback([trackLoc](const GameAction*, const TrackDesignActionResult* result) { + tdAction.SetCallback([trackLoc](const GameAction*, const GameActions::Result* result) { if (result->Error == GameActions::Status::Ok) { - auto ride = get_ride(result->rideIndex); + const auto rideId = result->GetData(); + auto ride = get_ride(rideId); if (ride != nullptr) { window_close_by_class(WC_ERROR); OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, trackLoc); - _currentRideIndex = result->rideIndex; + _currentRideIndex = rideId; if (track_design_are_entrance_and_exit_placed()) { auto intent = Intent(WC_RIDE); - intent.putExtra(INTENT_EXTRA_RIDE_ID, static_cast(result->rideIndex)); + intent.putExtra(INTENT_EXTRA_RIDE_ID, static_cast(rideId)); context_open_intent(&intent); auto wnd = window_find_by_class(WC_TRACK_DESIGN_PLACE); window_close(wnd); diff --git a/src/openrct2/actions/TrackDesignAction.cpp b/src/openrct2/actions/TrackDesignAction.cpp index 7964b99029..931a7fe85f 100644 --- a/src/openrct2/actions/TrackDesignAction.cpp +++ b/src/openrct2/actions/TrackDesignAction.cpp @@ -28,26 +28,6 @@ static int32_t place_virtual_track( return place_virtual_track(const_cast(&td6), ptdOperation, placeScenery, ride, loc); } -TrackDesignActionResult::TrackDesignActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_NONE) -{ -} - -TrackDesignActionResult::TrackDesignActionResult(GameActions::Status error) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE) -{ -} - -TrackDesignActionResult::TrackDesignActionResult(GameActions::Status error, rct_string_id title, rct_string_id message) - : GameActions::Result(error, title, message) -{ -} - -TrackDesignActionResult::TrackDesignActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message) -{ -} - TrackDesignAction::TrackDesignAction(const CoordsXYZD& location, const TrackDesign& td) : _loc(location) , _td(td) @@ -84,7 +64,7 @@ GameActions::Result::Ptr TrackDesignAction::Query() const if (!LocationValid(_loc)) { - return MakeResult(GameActions::Status::InvalidParameters); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); } auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); @@ -113,7 +93,7 @@ GameActions::Result::Ptr TrackDesignAction::Query() const if (ride == nullptr) { log_warning("Invalid game command for track placement, ride id = %d", rideIndex); - return MakeResult(GameActions::Status::Unknown); + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); } money32 cost = 0; @@ -133,9 +113,11 @@ GameActions::Result::Ptr TrackDesignAction::Query() const GameActions::ExecuteNested(&gameAction); if (cost == MONEY32_UNDEFINED) { - return MakeResult(GameActions::Status::Disallowed, error_reason); + return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, error_reason); } res->Cost = cost; + res->SetData(ride_id_t{ RIDE_ID_NULL }); + return res; } @@ -173,7 +155,7 @@ GameActions::Result::Ptr TrackDesignAction::Execute() const if (ride == nullptr) { log_warning("Invalid game command for track placement, ride id = %d", rideIndex); - return MakeResult(GameActions::Status::Unknown); + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); } money32 cost = 0; @@ -211,7 +193,7 @@ GameActions::Result::Ptr TrackDesignAction::Execute() const gameAction.SetFlags(GetFlags()); GameActions::ExecuteNested(&gameAction); - return MakeResult(GameActions::Status::Disallowed, error_reason); + return MakeResult(GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, error_reason); } if (entryIndex != OBJECT_ENTRY_INDEX_NULL) @@ -275,6 +257,7 @@ GameActions::Result::Ptr TrackDesignAction::Execute() const r = GameActions::ExecuteNested(&gameAction); } res->Cost = cost; - res->rideIndex = ride->id; + res->SetData(ride_id_t{ ride->id }); + return res; } diff --git a/src/openrct2/actions/TrackDesignAction.h b/src/openrct2/actions/TrackDesignAction.h index 1390bc3627..8ce73431f0 100644 --- a/src/openrct2/actions/TrackDesignAction.h +++ b/src/openrct2/actions/TrackDesignAction.h @@ -12,18 +12,7 @@ #include "../ride/TrackDesign.h" #include "GameAction.h" -class TrackDesignActionResult final : public GameActions::Result -{ -public: - TrackDesignActionResult(); - TrackDesignActionResult(GameActions::Status error); - TrackDesignActionResult(GameActions::Status error, rct_string_id title, rct_string_id message); - TrackDesignActionResult(GameActions::Status error, rct_string_id message); - - ride_id_t rideIndex = RIDE_ID_NULL; -}; - -DEFINE_GAME_ACTION(TrackDesignAction, GameCommand::PlaceTrackDesign, TrackDesignActionResult) +DEFINE_GAME_ACTION(TrackDesignAction, GameCommand::PlaceTrackDesign, GameActions::Result) { private: CoordsXYZD _loc; diff --git a/src/openrct2/actions/TrackPlaceAction.cpp b/src/openrct2/actions/TrackPlaceAction.cpp index c1287a714b..ec46e18123 100644 --- a/src/openrct2/actions/TrackPlaceAction.cpp +++ b/src/openrct2/actions/TrackPlaceAction.cpp @@ -21,25 +21,6 @@ #include "RideSetSettingAction.h" using namespace OpenRCT2::TrackMetaData; -TrackPlaceActionResult::TrackPlaceActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE) -{ -} - -TrackPlaceActionResult::TrackPlaceActionResult(GameActions::Status error) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE) -{ -} - -TrackPlaceActionResult::TrackPlaceActionResult(GameActions::Status error, rct_string_id message) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message) -{ -} - -TrackPlaceActionResult::TrackPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args) - : GameActions::Result(error, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, message, args) -{ -} TrackPlaceAction::TrackPlaceAction( NetworkRideId_t rideIndex, int32_t trackType, const CoordsXYZD& origin, int32_t brakeSpeed, int32_t colour, @@ -87,42 +68,44 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const if (ride == nullptr) { log_warning("Invalid ride for track placement, rideIndex = %d", EnumValue(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); } rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); if (rideEntry == nullptr) { log_warning("Invalid ride subtype for track placement, rideIndex = %d", EnumValue(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); } if (!direction_valid(_origin.direction)) { log_warning("Invalid direction for track placement, direction = %d", _origin.direction); - return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); } - auto res = std::make_unique(); + auto res = MakeResult(); res->Expenditure = ExpenditureType::RideConstruction; res->Position.x = _origin.x + 16; res->Position.y = _origin.y + 16; res->Position.z = _origin.z; - res->GroundFlags = 0; + auto resultData = TrackPlaceActionResult{}; uint32_t rideTypeFlags = ride->GetRideTypeDescriptor().Flags; if ((ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) && _trackType == TrackElemType::EndStation) { - return std::make_unique(GameActions::Status::Disallowed, STR_NOT_ALLOWED_TO_MODIFY_STATION); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NOT_ALLOWED_TO_MODIFY_STATION); } if (!(GetActionFlags() & GameActions::Flags::AllowWhilePaused)) { if (game_is_paused() && !gCheatsBuildInPauseMode) { - return std::make_unique( - GameActions::Status::Disallowed, STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED); } } @@ -132,16 +115,18 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const { if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) { - return std::make_unique( - GameActions::Status::Disallowed, STR_ONLY_ONE_ON_RIDE_PHOTO_PER_RIDE); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_ONLY_ONE_ON_RIDE_PHOTO_PER_RIDE); } } else if (_trackType == TrackElemType::CableLiftHill) { if (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED) { - return std::make_unique( - GameActions::Status::Disallowed, STR_ONLY_ONE_CABLE_LIFT_HILL_PER_RIDE); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_ONLY_ONE_CABLE_LIFT_HILL_PER_RIDE); } } // Backwards steep lift hills are allowed, even on roller coasters that do not support forwards steep lift hills. @@ -151,7 +136,9 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const const auto& ted = GetTrackElementDescriptor(_trackType); if (ted.Flags & TRACK_ELEM_FLAG_IS_STEEP_UP) { - return std::make_unique(GameActions::Status::Disallowed, STR_TOO_STEEP_FOR_LIFT_HILL); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_TOO_STEEP_FOR_LIFT_HILL); } } } @@ -168,7 +155,8 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const if (!LocationValid(tileCoords) || (!map_is_location_owned(tileCoords) && !gCheatsSandboxMode)) { - return std::make_unique(GameActions::Status::Disallowed, STR_LAND_NOT_OWNED_BY_PARK); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_LAND_NOT_OWNED_BY_PARK); } numElements++; } @@ -176,7 +164,9 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const if (!CheckMapCapacity(numElements)) { log_warning("Not enough free map elements to place track."); - return std::make_unique(GameActions::Status::NoFreeElements, STR_TILE_ELEMENT_LIMIT_REACHED); + return MakeResult( + GameActions::Status::NoFreeElements, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_TILE_ELEMENT_LIMIT_REACHED); } if (!gCheatsAllowTrackPlaceInvalidHeights) @@ -185,16 +175,18 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const { if ((_origin.z & 0x0F) != 8) { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CONSTRUCTION_ERR_UNKNOWN); + return MakeResult( + GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_CONSTRUCTION_ERR_UNKNOWN); } } else { if ((_origin.z & 0x0F) != 0) { - return std::make_unique( - GameActions::Status::InvalidParameters, STR_CONSTRUCTION_ERR_UNKNOWN); + return MakeResult( + GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_CONSTRUCTION_ERR_UNKNOWN); } } } @@ -210,7 +202,8 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const if (mapLoc.z < 16) { - return std::make_unique(GameActions::Status::InvalidParameters, STR_TOO_LOW); + return MakeResult( + GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_LOW); } int32_t baseZ = floor2(mapLoc.z, COORDS_Z_STEP); @@ -230,7 +223,8 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const if (clearanceZ > MAX_TRACK_HEIGHT) { - return std::make_unique(GameActions::Status::InvalidParameters, STR_TOO_HIGH); + return MakeResult( + GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_TOO_HIGH); } uint8_t crossingMode = (ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS) @@ -257,19 +251,21 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const } uint8_t mapGroundFlags = canBuild->GroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - if (res->GroundFlags != 0 && (res->GroundFlags & mapGroundFlags) == 0) + if (resultData.GroundFlags != 0 && (resultData.GroundFlags & mapGroundFlags) == 0) { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); } - res->GroundFlags = mapGroundFlags; + resultData.GroundFlags = mapGroundFlags; if (ted.Flags & TRACK_ELEM_FLAG_ONLY_ABOVE_GROUND) { - if (res->GroundFlags & ELEMENT_IS_UNDERGROUND) + if (resultData.GroundFlags & ELEMENT_IS_UNDERGROUND) { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND); } } @@ -277,34 +273,40 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const { // No element has this flag if (canBuild->GroundFlags & ELEMENT_IS_UNDERWATER) { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_UNDERWATER); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_CAN_ONLY_BUILD_THIS_UNDERWATER); } } if (canBuild->GroundFlags & ELEMENT_IS_UNDERWATER && !gCheatsDisableClearanceChecks) { - return std::make_unique( - GameActions::Status::Disallowed, STR_RIDE_CANT_BUILD_THIS_UNDERWATER); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_RIDE_CANT_BUILD_THIS_UNDERWATER); } if ((rideTypeFlags & RIDE_TYPE_FLAG_TRACK_MUST_BE_ON_WATER) && !_trackDesignDrawingPreview) { auto surfaceElement = map_get_surface_element_at(mapLoc); if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); + { + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); + } auto waterHeight = surfaceElement->GetWaterHeight(); if (waterHeight == 0) { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_CAN_ONLY_BUILD_THIS_ON_WATER); } if (waterHeight != baseZ) { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_CAN_ONLY_BUILD_THIS_ON_WATER); } waterHeight -= LAND_HEIGHT_STEP; if (waterHeight == surfaceElement->GetBaseZ()) @@ -313,8 +315,9 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const if (slope == TILE_ELEMENT_SLOPE_W_CORNER_DN || slope == TILE_ELEMENT_SLOPE_S_CORNER_DN || slope == TILE_ELEMENT_SLOPE_E_CORNER_DN || slope == TILE_ELEMENT_SLOPE_N_CORNER_DN) { - return std::make_unique( - GameActions::Status::Disallowed, STR_CAN_ONLY_BUILD_THIS_ON_WATER); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_CAN_ONLY_BUILD_THIS_ON_WATER); } } } @@ -324,14 +327,17 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const { if (!track_add_station_element({ mapLoc, baseZ, _origin.direction }, _rideIndex, 0, _fromTrackDesign)) { - return std::make_unique(GameActions::Status::Unknown, gGameCommandErrorText); + return MakeResult( + GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, gGameCommandErrorText); } } // 6c5648 12 push auto surfaceElement = map_get_surface_element_at(mapLoc); if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); + { + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); + } if (!gCheatsDisableSupportLimits) { @@ -353,7 +359,9 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const ride_height /= COORDS_Z_PER_TINY_Z; if (ride_height > maxHeight && !_trackDesignDrawingPreview) { - return std::make_unique(GameActions::Status::Disallowed, STR_TOO_HIGH_FOR_SUPPORTS); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_TOO_HIGH_FOR_SUPPORTS); } } } @@ -372,6 +380,8 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const price >>= 16; res->Cost = cost + ((price / 2) * 10); + res->SetData(std::move(resultData)); + return res; } @@ -381,23 +391,23 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const if (ride == nullptr) { log_warning("Invalid ride for track placement, rideIndex = %d", EnumValue(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); } rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); if (rideEntry == nullptr) { log_warning("Invalid ride subtype for track placement, rideIndex = %d", EnumValue(_rideIndex)); - return std::make_unique(GameActions::Status::InvalidParameters); + return MakeResult(GameActions::Status::InvalidParameters, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); } - auto res = std::make_unique(); + auto res = MakeResult(); res->Expenditure = ExpenditureType::RideConstruction; res->Position.x = _origin.x + 16; res->Position.y = _origin.y + 16; res->Position.z = _origin.z; - res->GroundFlags = 0; + auto resultData = TrackPlaceActionResult{}; uint32_t rideTypeFlags = ride->GetRideTypeDescriptor().Flags; @@ -466,18 +476,21 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const } uint8_t mapGroundFlags = canBuild->GroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - if (res->GroundFlags != 0 && (res->GroundFlags & mapGroundFlags) == 0) + if (resultData.GroundFlags != 0 && (resultData.GroundFlags & mapGroundFlags) == 0) { - return std::make_unique( - GameActions::Status::Disallowed, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); + return MakeResult( + GameActions::Status::Disallowed, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND); } - res->GroundFlags = mapGroundFlags; + resultData.GroundFlags = mapGroundFlags; // 6c5648 12 push auto surfaceElement = map_get_surface_element_at(mapLoc); if (surfaceElement == nullptr) - return std::make_unique(GameActions::Status::Unknown, STR_NONE); + { + return MakeResult(GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_NONE); + } int32_t supportHeight = baseZ - surfaceElement->GetBaseZ(); if (supportHeight < 0) @@ -552,7 +565,9 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const if (trackElement == nullptr) { log_warning("Cannot create track element for ride = %d", EnumValue(_rideIndex)); - return std::make_unique(GameActions::Status::NoFreeElements); + return MakeResult( + GameActions::Status::NoFreeElements, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, + STR_TILE_ELEMENT_LIMIT_REACHED); } trackElement->SetClearanceZ(clearanceZ); @@ -659,6 +674,8 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const price >>= 16; res->Cost = cost + ((price / 2) * 10); + res->SetData(std::move(resultData)); + return res; } diff --git a/src/openrct2/actions/TrackPlaceAction.h b/src/openrct2/actions/TrackPlaceAction.h index 8692372f16..2b2a59b8f1 100644 --- a/src/openrct2/actions/TrackPlaceAction.h +++ b/src/openrct2/actions/TrackPlaceAction.h @@ -11,18 +11,12 @@ #include "GameAction.h" -class TrackPlaceActionResult final : public GameActions::Result +struct TrackPlaceActionResult { -public: - TrackPlaceActionResult(); - TrackPlaceActionResult(GameActions::Status error); - TrackPlaceActionResult(GameActions::Status error, rct_string_id message); - TrackPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args); - uint8_t GroundFlags{ 0 }; }; -DEFINE_GAME_ACTION(TrackPlaceAction, GameCommand::PlaceTrack, TrackPlaceActionResult) +DEFINE_GAME_ACTION(TrackPlaceAction, GameCommand::PlaceTrack, GameActions::Result) { private: NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index a7f69be4a2..949363cc7a 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -1758,35 +1758,30 @@ Staff* ride_get_assigned_mechanic(Ride* ride) /** * - * rct2: 0x006ABE85 + * Calculates the sample rate for ride music. */ -static void ride_music_update(Ride* ride) +static int32_t RideMusicSampleRate(Ride* ride) { - // The circus does not have music in the normal sense - its “music” is a sound effect. - if (ride->type == RIDE_TYPE_CIRCUS) - { - Vehicle* vehicle = GetEntity(ride->vehicles[0]); - if (vehicle == nullptr || vehicle->status != Vehicle::Status::DoingCircusShow) - { - ride->music_tune_id = 255; - return; - } - } - else - { - const auto& rtd = ride->GetRideTypeDescriptor(); - if (!rtd.HasFlag(RIDE_TYPE_FLAG_MUSIC_ON_DEFAULT) && !rtd.HasFlag(RIDE_TYPE_FLAG_ALLOW_MUSIC)) - { - return; - } + int32_t sampleRate = 22050; - if (ride->status != RideStatus::Open || !(ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC)) - { - ride->music_tune_id = 255; - return; - } + // Alter sample rate for a power cut effect + if (ride->lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN)) + { + sampleRate = ride->breakdown_sound_modifier * 70; + if (ride->breakdown_reason_pending != BREAKDOWN_CONTROL_FAILURE) + sampleRate *= -1; + sampleRate += 22050; } + return sampleRate; +} + +/** + * + * Ride music slows down upon breaking. If it's completely broken, no music should play. + */ +static bool RideMusicBreakdownEffect(Ride* ride) +{ // Oscillate parameters for a power cut effect when breaking down if (ride->lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN)) { @@ -1809,10 +1804,67 @@ static void ride_music_update(Ride* ride) if (ride->breakdown_sound_modifier == 255) { ride->music_tune_id = 255; - return; + return true; } } } + return false; +} + +/** + * + * Circus music is a sound effect, rather than music. Needs separate processing. + */ +static void CircusMusicUpdate(Ride* ride) +{ + Vehicle* vehicle = GetEntity(ride->vehicles[0]); + if (vehicle == nullptr || vehicle->status != Vehicle::Status::DoingCircusShow) + { + ride->music_position = 0; + ride->music_tune_id = 255; + return; + } + + if (RideMusicBreakdownEffect(ride)) + { + return; + } + + CoordsXYZ rideCoords = ride->stations[0].GetStart().ToTileCentre(); + + const auto sampleRate = RideMusicSampleRate(ride); + + OpenRCT2::RideAudio::UpdateMusicInstance(*ride, rideCoords, sampleRate); +} + +/** + * + * rct2: 0x006ABE85 + */ +static void ride_music_update(Ride* ride) +{ + if (ride->type == RIDE_TYPE_CIRCUS) + { + CircusMusicUpdate(ride); + return; + } + + const auto& rtd = ride->GetRideTypeDescriptor(); + if (!rtd.HasFlag(RIDE_TYPE_FLAG_MUSIC_ON_DEFAULT) && !rtd.HasFlag(RIDE_TYPE_FLAG_ALLOW_MUSIC)) + { + return; + } + + if (ride->status != RideStatus::Open || !(ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC)) + { + ride->music_tune_id = 255; + return; + } + + if (RideMusicBreakdownEffect(ride)) + { + return; + } // Select random tune from available tunes for a music style (of course only merry-go-rounds have more than one tune) if (ride->music_tune_id == 255) @@ -1830,16 +1882,7 @@ static void ride_music_update(Ride* ride) CoordsXYZ rideCoords = ride->stations[0].GetStart().ToTileCentre(); - int32_t sampleRate = 22050; - - // Alter sample rate for a power cut effect - if (ride->lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN)) - { - sampleRate = ride->breakdown_sound_modifier * 70; - if (ride->breakdown_reason_pending != BREAKDOWN_CONTROL_FAILURE) - sampleRate *= -1; - sampleRate += 22050; - } + int32_t sampleRate = RideMusicSampleRate(ride); OpenRCT2::RideAudio::UpdateMusicInstance(*ride, rideCoords, sampleRate); } diff --git a/src/openrct2/windows/_legacy.cpp b/src/openrct2/windows/_legacy.cpp index 96f0a9e519..df54293b1b 100644 --- a/src/openrct2/windows/_legacy.cpp +++ b/src/openrct2/windows/_legacy.cpp @@ -51,13 +51,12 @@ money32 place_provisional_track_piece( if (ride == nullptr) return MONEY32_UNDEFINED; - money32 result; ride_construction_remove_ghosts(); if (ride->type == RIDE_TYPE_MAZE) { int32_t flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST; // 105 - result = maze_set_track(trackPos.x, trackPos.y, trackPos.z, flags, true, 0, rideIndex, GC_SET_MAZE_TRACK_BUILD); + auto result = maze_set_track(trackPos.x, trackPos.y, trackPos.z, flags, true, 0, rideIndex, GC_SET_MAZE_TRACK_BUILD); if (result == MONEY32_UNDEFINED) return result; @@ -84,10 +83,8 @@ money32 place_provisional_track_piece( trackPlaceAction.SetFlags(GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST); // This command must not be sent over the network auto res = GameActions::Execute(&trackPlaceAction); - auto tpar = dynamic_cast(res.get()); - result = ((tpar == nullptr) || (res->Error == GameActions::Status::Ok)) ? res->Cost : MONEY32_UNDEFINED; - if (result == MONEY32_UNDEFINED) - return result; + if (res->Error != GameActions::Status::Ok) + return MONEY32_UNDEFINED; int16_t z_begin, z_end; const auto& ted = GetTrackElementDescriptor(trackType); @@ -104,10 +101,9 @@ money32 place_provisional_track_piece( _unkF440C5 = { trackPos.x, trackPos.y, trackPos.z + z_begin, static_cast(trackDirection) }; _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_TRACK; - if (tpar != nullptr) - { - viewport_set_visibility((tpar->GroundFlags & ELEMENT_IS_UNDERGROUND) ? 1 : 3); - } + + const auto resultData = res->GetData(); + viewport_set_visibility((resultData.GroundFlags & ELEMENT_IS_UNDERGROUND) ? 1 : 3); if (_currentTrackSlopeEnd != 0) viewport_set_visibility(2); @@ -120,7 +116,7 @@ money32 place_provisional_track_piece( virtual_floor_set_height(trackPos.z - z_begin + z_end); } - return result; + return res->Cost; } static std::tuple window_ride_construction_update_state_get_track_element()