From 08cb8cb8c3fd8d3ef34a409b028626a105016d3e Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 30 Apr 2025 16:41:47 +0200 Subject: [PATCH] Add plugin call for breakdowns (#24207) --- distribution/changelog.txt | 1 + distribution/openrct2.d.ts | 19 +++++++ src/openrct2/scripting/ScriptEngine.h | 2 +- .../scripting/bindings/ride/ScRide.cpp | 53 +++++++++++++++++++ .../scripting/bindings/ride/ScRide.hpp | 6 +++ 5 files changed, 80 insertions(+), 1 deletion(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 73e676ee6a..e52eb89864 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,5 +1,6 @@ 0.4.22 (in development) ------------------------------------------------------------------------ +- Feature: [#24206] [Plugin] Add APIs for breaking down rides, reading the current breakdown, and for fixing broken down rides. - Improved: [#20073] The OpenGL drawing engine now supports screen invalidation which avoids the redrawing of unchanged regions. - Improved: [#21767] RCT Classic for macOS can now be used as the source game. - Improved: [#23590] Title bars are now drawn bigger when “Enlarged UI” is enabled. diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index d333aa1c67..4f93f89edd 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -2501,11 +2501,30 @@ declare global { * Highest drop height in height units. Use `context.formatString()` to convert into metres/feet. Ex: `formatString('{HEIGHT}', ride.highestDropHeight)`. */ readonly highestDropHeight: number; + + /** + * The current breakdown of the ride. + */ + readonly breakdown: BreakdownType; + + /** + * Set a breakdown on a ride. + * @param breakdown The type of breakdown to set. + */ + setBreakdown(breakdown: BreakdownType): void; + + /** + * Fix a ride / clear the breakdown. + */ + fixBreakdown(): void; + } type RideClassification = "ride" | "stall" | "facility"; type RideStatus = "closed" | "open" | "testing" | "simulating"; + + type BreakdownType = "brakes_failure" | "control_failure" | "doors_stuck_closed" | "doors_stuck_open" | "restraints_stuck_closed" | "restraints_stuck_open" | "safety_cut_out" | "vehicle_malfunction"; interface TrackColour { main: number; diff --git a/src/openrct2/scripting/ScriptEngine.h b/src/openrct2/scripting/ScriptEngine.h index b7a10f1746..92accb182b 100644 --- a/src/openrct2/scripting/ScriptEngine.h +++ b/src/openrct2/scripting/ScriptEngine.h @@ -46,7 +46,7 @@ namespace OpenRCT2 namespace OpenRCT2::Scripting { - static constexpr int32_t kPluginApiVersion = 106; + static constexpr int32_t kPluginApiVersion = 107; // Versions marking breaking changes. static constexpr int32_t kApiVersionPeepDeprecation = 33; diff --git a/src/openrct2/scripting/bindings/ride/ScRide.cpp b/src/openrct2/scripting/bindings/ride/ScRide.cpp index c2bfa6d0fa..ec4c9ecfba 100644 --- a/src/openrct2/scripting/bindings/ride/ScRide.cpp +++ b/src/openrct2/scripting/bindings/ride/ScRide.cpp @@ -21,6 +21,16 @@ namespace OpenRCT2::Scripting { + static const DukEnumMap BreakdownMap // The types of breakdowns. + ({ { "safety_cut_out", BREAKDOWN_SAFETY_CUT_OUT }, + { "restraints_stuck_closed", BREAKDOWN_RESTRAINTS_STUCK_CLOSED }, + { "restraints_stuck_open", BREAKDOWN_RESTRAINTS_STUCK_OPEN }, + { "doors_stuck_closed", BREAKDOWN_DOORS_STUCK_CLOSED }, + { "doors_stuck_open", BREAKDOWN_DOORS_STUCK_OPEN }, + { "vehicle_malfunction", BREAKDOWN_VEHICLE_MALFUNCTION }, + { "brakes_failure", BREAKDOWN_BRAKES_FAILURE }, + { "control_failure", BREAKDOWN_CONTROL_FAILURE } }); + ScRide::ScRide(RideId rideId) : _rideId(rideId) { @@ -489,6 +499,46 @@ namespace OpenRCT2::Scripting return ::GetRide(_rideId); } + void ScRide::SetBreakdown(const std::string& breakDown) + { + ThrowIfGameStateNotMutable(); + auto ride = GetRide(); + if (ride != nullptr && ride->canBreakDown() && ride->status == RideStatus::open) + { + auto it = BreakdownMap.find(breakDown); + if (it == BreakdownMap.end()) + return; + RidePrepareBreakdown(*ride, it->second); + } + } + + void ScRide::FixBreakdown() + { + ThrowIfGameStateNotMutable(); + auto ride = GetRide(); + if (ride != nullptr && ride->canBreakDown()) + { + RideFixBreakdown(*ride, 0); + } + } + + std::string ScRide::getBreakdown() const + { + auto ride = GetRide(); + + if (ride != nullptr) + { + if (!(ride->lifecycleFlags & RIDE_LIFECYCLE_BROKEN_DOWN)) + { + return "none"; + } + auto it = BreakdownMap.find(ride->breakdownReason); + if (it != BreakdownMap.end()) + return std::string(it->first); + } + return ""; + } + uint8_t ScRide::downtime_get() const { auto ride = GetRide(); @@ -642,6 +692,9 @@ namespace OpenRCT2::Scripting dukglue_register_property(ctx, &ScRide::numDrops_get, nullptr, "numDrops"); dukglue_register_property(ctx, &ScRide::numLiftHills_get, nullptr, "numLiftHills"); dukglue_register_property(ctx, &ScRide::highestDropHeight_get, nullptr, "highestDropHeight"); + dukglue_register_property(ctx, &ScRide::getBreakdown, nullptr, "breakdown"); + dukglue_register_method(ctx, &ScRide::SetBreakdown, "setBreakdown"); + dukglue_register_method(ctx, &ScRide::FixBreakdown, "fixBreakdown"); } } // namespace OpenRCT2::Scripting diff --git a/src/openrct2/scripting/bindings/ride/ScRide.hpp b/src/openrct2/scripting/bindings/ride/ScRide.hpp index fcff9e1cdc..e357e276c6 100644 --- a/src/openrct2/scripting/bindings/ride/ScRide.hpp +++ b/src/openrct2/scripting/bindings/ride/ScRide.hpp @@ -192,6 +192,12 @@ namespace OpenRCT2::Scripting Ride* GetRide() const; + void SetBreakdown(const std::string& breakDown); + + void FixBreakdown(); + + std::string getBreakdown() const; + public: static void Register(duk_context* ctx); };