From 6e7b4893040c9192373f0ec1c650fdd1eb54f9df Mon Sep 17 00:00:00 2001 From: AT41 Date: Thu, 3 Oct 2024 05:23:50 -0600 Subject: [PATCH] Added additional stats to Plugin interface Co-authored-by: Tulio Leao --- distribution/changelog.txt | 1 + distribution/openrct2.d.ts | 57 +++++++++++++- src/openrct2-ui/windows/InstallTrack.cpp | 6 +- src/openrct2-ui/windows/Ride.cpp | 8 +- src/openrct2-ui/windows/TrackList.cpp | 6 +- src/openrct2/localisation/FormatCodes.cpp | 2 + src/openrct2/localisation/FormatCodes.h | 1 + src/openrct2/localisation/Formatting.cpp | 18 +++++ src/openrct2/rct2/RCT2.h | 3 +- src/openrct2/ride/Ride.h | 3 +- src/openrct2/ride/RideRatings.cpp | 14 ++-- src/openrct2/ride/TrackDesign.cpp | 2 +- src/openrct2/scenario/Scenario.cpp | 2 +- src/openrct2/scripting/ScriptEngine.h | 2 +- .../scripting/bindings/ride/ScRide.cpp | 77 +++++++++++++++++++ .../scripting/bindings/ride/ScRide.hpp | 22 ++++++ src/openrct2/util/Util.cpp | 23 ++++++ src/openrct2/util/Util.h | 4 + test/tests/FormattingTests.cpp | 2 +- 19 files changed, 228 insertions(+), 25 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 42b175822b..63f3773c4f 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -2,6 +2,7 @@ ------------------------------------------------------------------------ - Feature: [#775] Add 2x and 4x zoom levels to software renderer (previously limited to OpenGL). - Feature: [#15642] Track design placement can now use construction modifier keys (ctrl/shift). +- Feature: [#20539] [Plugin] Add API for getting a ride’s statistics. - Feature: [#21521] [Plugin] Add hook 'park.guest.softcap.calculate' called before calculating the soft guest cap. - Feature: [#22383] Add downward-inclined brakes to hybrid coaster and single rail coaster. - Feature: [#22694] Park graphs have tooltips and can be resized like finance graphs. diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index f4a42020a6..e9cf212c4d 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -2163,7 +2163,7 @@ declare global { readonly downtime: number; /** - * The currently set chain lift speed in miles per hour. + * The currently set chain lift speed in miles per hour. Use `context.formatString()` to convert speed values to a localised value/unit string. Ex: `formatString('{VELOCITY}', ride.liftHillSpeed)`. */ liftHillSpeed: number; @@ -2181,6 +2181,61 @@ declare global { * The satisfaction rating of the ride from 0 to 100. */ readonly satisfaction: number; + + /** + * The max speed in miles per hour. + */ + readonly maxSpeed: number; + + /** + * The average speed in miles per hour. + */ + readonly averageSpeed: number; + + /** + * The ride time in seconds. + */ + readonly rideTime: number; + + /** + * Total length of the ride in meters. Use `context.formatString()` to convert into localised value/unit string. Ex: `formatString('{LENGTH}', ride.rideLength)`. + */ + readonly rideLength: number; + + /** + * The max positive vertical Gs. + */ + readonly maxPositiveVerticalGs: number; + + /** + * The max negative vertical Gs. + */ + readonly maxNegativeVerticalGs: number; + + /** + * The max lateral Gs. + */ + readonly maxLateralGs: number; + + /** + * The total airtime in seconds. + */ + readonly totalAirTime: number; + + /** + * The number of drops. + */ + readonly numDrops: number; + + /** + * The number of lift hills. + */ + readonly numLiftHills: number; + + /** + * Highest drop height in height units. Use `context.formatString()` to convert into metres/feet. Ex: `formatString('{HEIGHT}', ride.highestDropHeight)`. + */ + readonly highestDropHeight: number; } type RideClassification = "ride" | "stall" | "facility"; diff --git a/src/openrct2-ui/windows/InstallTrack.cpp b/src/openrct2-ui/windows/InstallTrack.cpp index 337827f379..ac0dc485ff 100644 --- a/src/openrct2-ui/windows/InstallTrack.cpp +++ b/src/openrct2-ui/windows/InstallTrack.cpp @@ -253,7 +253,7 @@ namespace OpenRCT2::Ui::Windows { // Maximum speed { - uint16_t speed = ((td.statistics.maxSpeed << 16) * 9) >> 18; + uint16_t speed = ToHumanReadableSpeed(td.statistics.maxSpeed << 16); auto ft = Formatter(); ft.Add(speed); DrawTextBasic(dpi, screenPos, STR_MAX_SPEED, ft); @@ -261,7 +261,7 @@ namespace OpenRCT2::Ui::Windows } // Average speed { - uint16_t speed = ((td.statistics.averageSpeed << 16) * 9) >> 18; + uint16_t speed = ToHumanReadableSpeed(td.statistics.averageSpeed << 16); auto ft = Formatter(); ft.Add(speed); DrawTextBasic(dpi, screenPos, STR_AVERAGE_SPEED, ft); @@ -305,7 +305,7 @@ namespace OpenRCT2::Ui::Windows } if (td.statistics.totalAirTime != 0) { - int32_t airTime = td.statistics.totalAirTime * 3; + int32_t airTime = ToHumanReadableAirTime(td.statistics.totalAirTime); auto ft = Formatter(); ft.Add(airTime); DrawTextBasic(dpi, screenPos, STR_TOTAL_AIR_TIME, ft); diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp index cde7c29a41..fa46041d9c 100644 --- a/src/openrct2-ui/windows/Ride.cpp +++ b/src/openrct2-ui/windows/Ride.cpp @@ -2511,7 +2511,7 @@ namespace OpenRCT2::Ui::Windows } ft.Add(stringId); - uint16_t speedInMph = (abs(vehicle->velocity) * 9) >> 18; + uint16_t speedInMph = ToHumanReadableSpeed(abs(vehicle->velocity)); ft.Add(speedInMph); const RideComponentName stationName = GetRideComponentName(ride->GetRideTypeDescriptor().NameConvention.station); ft.Add(ride->num_stations > 1 ? stationName.number : stationName.singular); @@ -5731,13 +5731,13 @@ namespace OpenRCT2::Ui::Windows { // Max speed ft = Formatter(); - ft.Add((ride->max_speed * 9) >> 18); + ft.Add(ToHumanReadableSpeed(ride->max_speed)); DrawTextBasic(dpi, screenCoords, STR_MAX_SPEED, ft); screenCoords.y += kListRowHeight; // Average speed ft = Formatter(); - ft.Add((ride->average_speed * 9) >> 18); + ft.Add(ToHumanReadableSpeed(ride->average_speed)); DrawTextBasic(dpi, screenCoords, STR_AVERAGE_SPEED, ft); screenCoords.y += kListRowHeight; @@ -5851,7 +5851,7 @@ namespace OpenRCT2::Ui::Windows // Total 'air' time ft = Formatter(); - ft.Add(ride->totalAirTime * 3); + ft.Add(ToHumanReadableAirTime(ride->totalAirTime)); DrawTextBasic(dpi, screenCoords, STR_TOTAL_AIR_TIME, ft); screenCoords.y += kListRowHeight; } diff --git a/src/openrct2-ui/windows/TrackList.cpp b/src/openrct2-ui/windows/TrackList.cpp index 5abb15d3f1..30da441681 100644 --- a/src/openrct2-ui/windows/TrackList.cpp +++ b/src/openrct2-ui/windows/TrackList.cpp @@ -575,13 +575,13 @@ namespace OpenRCT2::Ui::Windows { // Maximum speed ft = Formatter(); - ft.Add(((_loadedTrackDesign->statistics.maxSpeed << 16) * 9) >> 18); + ft.Add(ToHumanReadableSpeed(_loadedTrackDesign->statistics.maxSpeed << 16)); DrawTextBasic(dpi, screenPos, STR_MAX_SPEED, ft); screenPos.y += kListRowHeight; // Average speed ft = Formatter(); - ft.Add(((_loadedTrackDesign->statistics.averageSpeed << 16) * 9) >> 18); + ft.Add(ToHumanReadableSpeed(_loadedTrackDesign->statistics.averageSpeed << 16)); DrawTextBasic(dpi, screenPos, STR_AVERAGE_SPEED, ft); screenPos.y += kListRowHeight; } @@ -618,7 +618,7 @@ namespace OpenRCT2::Ui::Windows { // Total air time ft = Formatter(); - ft.Add(_loadedTrackDesign->statistics.totalAirTime * 3); + ft.Add(ToHumanReadableAirTime(_loadedTrackDesign->statistics.totalAirTime)); DrawTextBasic(dpi, screenPos, STR_TOTAL_AIR_TIME, ft); screenPos.y += kListRowHeight; } diff --git a/src/openrct2/localisation/FormatCodes.cpp b/src/openrct2/localisation/FormatCodes.cpp index ce2b489442..82f64d0614 100644 --- a/src/openrct2/localisation/FormatCodes.cpp +++ b/src/openrct2/localisation/FormatCodes.cpp @@ -46,6 +46,7 @@ static const EnumMap FormatTokenMap = { { "DURATION", FormatToken::DurationShort, }, { "REALTIME", FormatToken::DurationLong, }, { "LENGTH", FormatToken::Length, }, + { "HEIGHT", FormatToken::Height, }, { "SPRITE", FormatToken::Sprite, }, { "BLACK", FormatToken::ColourBlack, }, { "GREY", FormatToken::ColourGrey, }, @@ -105,6 +106,7 @@ bool FormatTokenTakesArgument(FormatToken token) case FormatToken::DurationShort: case FormatToken::DurationLong: case FormatToken::Length: + case FormatToken::Height: case FormatToken::Sprite: return true; default: diff --git a/src/openrct2/localisation/FormatCodes.h b/src/openrct2/localisation/FormatCodes.h index 7a1ed89cf8..bb53efb2b7 100644 --- a/src/openrct2/localisation/FormatCodes.h +++ b/src/openrct2/localisation/FormatCodes.h @@ -43,6 +43,7 @@ enum class FormatToken DurationShort, DurationLong, Length, + Height, Sprite, Pop16, Push16, diff --git a/src/openrct2/localisation/Formatting.cpp b/src/openrct2/localisation/Formatting.cpp index 3fd3a6d143..fd66a30c8d 100644 --- a/src/openrct2/localisation/Formatting.cpp +++ b/src/openrct2/localisation/Formatting.cpp @@ -590,6 +590,23 @@ namespace OpenRCT2 } } break; + case FormatToken::Height: + if constexpr (std::is_integral()) + { + auto metres = HeightUnitsToMetres(arg); + switch (Config::Get().general.MeasurementFormat) + { + default: + case MeasurementFormat::Imperial: + FormatStringID(ss, STR_UNIT_SUFFIX_FEET, MetresToFeet(metres)); + break; + case MeasurementFormat::Metric: + case MeasurementFormat::SI: + FormatStringID(ss, STR_UNIT_SUFFIX_METRES, metres); + break; + } + } + break; case FormatToken::MonthYear: case FormatToken::MonthYearSentence: if constexpr (std::is_integral()) @@ -795,6 +812,7 @@ namespace OpenRCT2 break; case FormatToken::Comma16: case FormatToken::Length: + case FormatToken::Height: case FormatToken::Comma1dp16: anyArgs.emplace_back(ReadFromArgs(args)); break; diff --git a/src/openrct2/rct2/RCT2.h b/src/openrct2/rct2/RCT2.h index 719da26f88..0994924a1b 100644 --- a/src/openrct2/rct2/RCT2.h +++ b/src/openrct2/rct2/RCT2.h @@ -137,8 +137,7 @@ namespace OpenRCT2::RCT2 // bit 7: whirlpool uint8_t SpecialTrackElements; // 0x0D5 uint8_t Pad0D6[2]; // 0x0D6 - // Divide this value by 29127 to get the human-readable max speed - // (in RCT2, display_speed = (max_speed * 9) >> 18) + // Use ToHumanReadableSpeed if converting to display int32_t MaxSpeed; // 0x0D8 int32_t AverageSpeed; // 0x0DC uint8_t CurrentTestSegment; // 0x0E0 diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index 0b90738aee..3899b1937b 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -166,8 +166,7 @@ struct Ride // bit 6: log reverser, waterfall // bit 7: whirlpool uint8_t special_track_elements{}; - // Divide this value by 29127 to get the human-readable max speed - // (in RCT2, display_speed = (max_speed * 9) >> 18) + // Use ToHumanReadableSpeed if converting to display int32_t max_speed{}; int32_t average_speed{}; uint8_t current_test_segment{}; diff --git a/src/openrct2/ride/RideRatings.cpp b/src/openrct2/ride/RideRatings.cpp index ddda8b0ee6..3c3d38c656 100644 --- a/src/openrct2/ride/RideRatings.cpp +++ b/src/openrct2/ride/RideRatings.cpp @@ -1197,7 +1197,7 @@ static money64 RideComputeUpkeep(RideRatingUpdateState& state, const Ride& ride) auto trackCost = ride.GetRideTypeDescriptor().UpkeepCosts.CostPerTrackPiece; upkeep += trackCost * ride.getNumPoweredLifts(); - uint32_t totalLength = ride.GetTotalLength() >> 16; + uint32_t totalLength = ToHumanReadableRideLength(ride.GetTotalLength()); // The data originally here was 20's and 0's. The 20's all represented // rides that had tracks. The 0's were fixed rides like crooked house or @@ -1833,7 +1833,9 @@ static void RideRatingsAdd(RatingTuple& ratings, int32_t excitement, int32_t int static void RideRatingsApplyBonusLength(RatingTuple& ratings, const Ride& ride, RatingsModifier modifier) { - RideRatingsAdd(ratings, (std::min(ride.GetTotalLength() >> 16, modifier.threshold) * modifier.excitement) >> 16, 0, 0); + RideRatingsAdd( + ratings, (std::min(ToHumanReadableRideLength(ride.GetTotalLength()), modifier.threshold) * modifier.excitement) >> 16, + 0, 0); } static void RideRatingsApplyBonusSynchronisation(RatingTuple& ratings, const Ride& ride, RatingsModifier modifier) @@ -1936,7 +1938,7 @@ static void RideRatingsApplyBonusGoKartRace(RatingTuple& ratings, const Ride& ri static void RideRatingsApplyBonusTowerRide(RatingTuple& ratings, const Ride& ride, RatingsModifier modifier) { - int32_t lengthFactor = (ride.GetTotalLength() >> 16); + int32_t lengthFactor = ToHumanReadableRideLength(ride.GetTotalLength()); RideRatingsAdd( ratings, (lengthFactor * modifier.excitement) >> 16, (lengthFactor * modifier.intensity) >> 16, (lengthFactor * modifier.nausea) >> 16); @@ -1944,7 +1946,7 @@ static void RideRatingsApplyBonusTowerRide(RatingTuple& ratings, const Ride& rid static void RideRatingsApplyBonusRotoDrop(RatingTuple& ratings, const Ride& ride) { - int32_t lengthFactor = ((ride.GetTotalLength() >> 16) * 209715) >> 16; + int32_t lengthFactor = (ToHumanReadableRideLength(ride.GetTotalLength()) * 209715) >> 16; RideRatingsAdd(ratings, lengthFactor, lengthFactor * 2, lengthFactor * 2); } @@ -2062,7 +2064,7 @@ static void RideRatingsApplyBonusOperationOptionFreefall(RatingTuple& ratings, c static void RideRatingsApplyBonusLaunchedFreefallSpecial( RatingTuple& ratings, const Ride& ride, RideRatingUpdateState& state, RatingsModifier modifier) { - int32_t excitement = ((ride.GetTotalLength() >> 16) * 32768) >> 16; + int32_t excitement = (ToHumanReadableRideLength(ride.GetTotalLength()) * 32768) >> 16; RideRatingsAdd(ratings, excitement, 0, 0); #ifdef ORIGINAL_RATINGS @@ -2078,7 +2080,7 @@ static void RideRatingsApplyBonusLaunchedFreefallSpecial( // Fix #3282: When the ride mode is in downward launch mode, the intensity and // nausea were fixed regardless of how high the ride is. The following // calculation is based on roto-drop which is a similar mechanic. - int32_t lengthFactor = ((ride.GetTotalLength() >> 16) * 209715) >> 16; + int32_t lengthFactor = (ToHumanReadableRideLength(ride.GetTotalLength()) * 209715) >> 16; RideRatingsAdd(ratings, lengthFactor, lengthFactor * 2, lengthFactor * 2); } #endif diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index f8bbacf336..376cef2df9 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -151,7 +151,7 @@ ResultWithMessage TrackDesign::CreateTrackDesign(TrackDesignState& tds, const Ri appearance.stationObjectIdentifier = TrackDesignGetStationObjectIdentifier(ride); statistics.maxSpeed = static_cast(ride.max_speed / 65536); statistics.averageSpeed = static_cast(ride.average_speed / 65536); - statistics.rideLength = ride.GetTotalLength() / 65536; + statistics.rideLength = ToHumanReadableRideLength(ride.GetTotalLength()); statistics.maxPositiveVerticalG = ride.max_positive_vertical_g; statistics.maxNegativeVerticalG = ride.max_negative_vertical_g; statistics.maxLateralG = ride.max_lateral_g; diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 69333bf3a8..f10562b086 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -769,7 +769,7 @@ ObjectiveStatus Objective::Check10RollerCoastersLength() const { if (RideEntryHasCategory(*rideEntry, RIDE_CATEGORY_ROLLERCOASTER) && !type_already_counted[ride.subtype]) { - if ((ride.GetTotalLength() >> 16) >= MinimumLength) + if (ToHumanReadableRideLength(ride.GetTotalLength()) >= MinimumLength) { type_already_counted[ride.subtype] = true; rcs++; diff --git a/src/openrct2/scripting/ScriptEngine.h b/src/openrct2/scripting/ScriptEngine.h index fb79961d21..9bab44c971 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 OPENRCT2_PLUGIN_API_VERSION = 101; + static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 102; // Versions marking breaking changes. static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33; diff --git a/src/openrct2/scripting/bindings/ride/ScRide.cpp b/src/openrct2/scripting/bindings/ride/ScRide.cpp index cade909ad1..e50dda64a0 100644 --- a/src/openrct2/scripting/bindings/ride/ScRide.cpp +++ b/src/openrct2/scripting/bindings/ride/ScRide.cpp @@ -529,6 +529,72 @@ namespace OpenRCT2::Scripting return ride != nullptr ? ride->satisfaction * 5 : 0; } + double ScRide::maxSpeed_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ToHumanReadableSpeed(ride->max_speed) : 0; + } + + double ScRide::averageSpeed_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ToHumanReadableSpeed(ride->average_speed) : 0; + } + + int32_t ScRide::rideTime_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ride->GetTotalTime() : 0; + } + + double ScRide::rideLength_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ToHumanReadableRideLength(ride->GetTotalLength()) : 0; + } + + double ScRide::maxPositiveVerticalGs_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ride->max_positive_vertical_g / 100.0 : 0; + } + + double ScRide::maxNegativeVerticalGs_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ride->max_negative_vertical_g / 100.0 : 0; + } + + double ScRide::maxLateralGs_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ride->max_lateral_g / 100.0 : 0; + } + + double ScRide::totalAirTime_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ToHumanReadableAirTime(ride->totalAirTime) / 100.0 : 0; + } + + uint8_t ScRide::numDrops_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ride->getNumDrops() : 0; + } + + uint8_t ScRide::numLiftHills_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ride->getNumPoweredLifts() : 0; + } + + double ScRide::highestDropHeight_get() const + { + auto ride = GetRide(); + return ride != nullptr ? ride->highest_drop_height : 0; + } + void ScRide::Register(duk_context* ctx) { dukglue_register_property(ctx, &ScRide::id_get, nullptr, "id"); @@ -564,6 +630,17 @@ namespace OpenRCT2::Scripting dukglue_register_property(ctx, &ScRide::maxLiftHillSpeed_get, nullptr, "maxLiftHillSpeed"); dukglue_register_property(ctx, &ScRide::minLiftHillSpeed_get, nullptr, "minLiftHillSpeed"); dukglue_register_property(ctx, &ScRide::satisfaction_get, nullptr, "satisfaction"); + dukglue_register_property(ctx, &ScRide::maxSpeed_get, nullptr, "maxSpeed"); + dukglue_register_property(ctx, &ScRide::averageSpeed_get, nullptr, "averageSpeed"); + dukglue_register_property(ctx, &ScRide::rideTime_get, nullptr, "rideTime"); + dukglue_register_property(ctx, &ScRide::rideLength_get, nullptr, "rideLength"); + dukglue_register_property(ctx, &ScRide::maxPositiveVerticalGs_get, nullptr, "maxPositiveVerticalGs"); + dukglue_register_property(ctx, &ScRide::maxNegativeVerticalGs_get, nullptr, "maxNegativeVerticalGs"); + dukglue_register_property(ctx, &ScRide::maxLateralGs_get, nullptr, "maxLateralGs"); + dukglue_register_property(ctx, &ScRide::totalAirTime_get, nullptr, "totalAirTime"); + 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"); } } // namespace OpenRCT2::Scripting diff --git a/src/openrct2/scripting/bindings/ride/ScRide.hpp b/src/openrct2/scripting/bindings/ride/ScRide.hpp index 6aded20cb9..53e78f93ef 100644 --- a/src/openrct2/scripting/bindings/ride/ScRide.hpp +++ b/src/openrct2/scripting/bindings/ride/ScRide.hpp @@ -164,6 +164,28 @@ namespace OpenRCT2::Scripting uint8_t satisfaction_get() const; + double maxSpeed_get() const; + + double averageSpeed_get() const; + + int32_t rideTime_get() const; + + double rideLength_get() const; + + double maxPositiveVerticalGs_get() const; + + double maxNegativeVerticalGs_get() const; + + double maxLateralGs_get() const; + + double totalAirTime_get() const; + + uint8_t numDrops_get() const; + + uint8_t numLiftHills_get() const; + + double highestDropHeight_get() const; + Ride* GetRide() const; public: diff --git a/src/openrct2/util/Util.cpp b/src/openrct2/util/Util.cpp index fcaf6703a1..0ac29fe1ef 100644 --- a/src/openrct2/util/Util.cpp +++ b/src/openrct2/util/Util.cpp @@ -67,6 +67,29 @@ uint8_t MetresToBaseZ(int16_t metres) return ((metres / 1.5) + 7) * 2; } +int32_t HeightUnitsToMetres(int32_t heightUnit) +{ + // 1 unit = 0.75 metres + return (heightUnit * 3) >> 2; +} + +int32_t ToHumanReadableSpeed(int32_t baseSpeed) +{ + // Divide this value by 29127 to get the human-readable max speed + // (in RCT2, display_speed = (max_speed * 9) >> 18) + return (baseSpeed * 9) >> 18; +} + +uint16_t ToHumanReadableAirTime(uint16_t airTime) +{ + return airTime * 3; +} + +int32_t ToHumanReadableRideLength(int32_t rideLength) +{ + return rideLength >> 16; +} + /* Case insensitive logical compare */ // Example: // - Guest 10 diff --git a/src/openrct2/util/Util.h b/src/openrct2/util/Util.h index b94e51042d..94af6c5d43 100644 --- a/src/openrct2/util/Util.h +++ b/src/openrct2/util/Util.h @@ -30,6 +30,10 @@ int32_t MphToKmph(int32_t mph); int32_t MphToDmps(int32_t mph); int32_t BaseZToMetres(int16_t baseZ); uint8_t MetresToBaseZ(int16_t metres); +int32_t HeightUnitsToMetres(int32_t heightUnit); +int32_t ToHumanReadableSpeed(int32_t baseSpeed); +uint16_t ToHumanReadableAirTime(uint16_t airTime); +int32_t ToHumanReadableRideLength(int32_t rideLength); inline int32_t UtilBitScanForward(uint32_t source) { diff --git a/test/tests/FormattingTests.cpp b/test/tests/FormattingTests.cpp index 5e6fcd950c..a425ed4ad7 100644 --- a/test/tests/FormattingTests.cpp +++ b/test/tests/FormattingTests.cpp @@ -42,7 +42,7 @@ TEST_F(FmtStringTests, iteration) actual += String::StdFormat("[%d:%s]", t.kind, std::string(t.text).c_str()); } - ASSERT_EQ("[30:{BLACK}][1:Guests: ][8:{INT32}]", actual); + ASSERT_EQ("[31:{BLACK}][1:Guests: ][8:{INT32}]", actual); } TEST_F(FmtStringTests, iteration_escaped)