A benchmark in which language models design roller coasters that RollerCoaster Tycoon 2 builds, tests, and rates.
I'll start by checking the coaster tools and looking at the engine source for what excitement rewards.
{"max_results":15,"query":"coaster new_ride place_piece finish_and_test"}
{"command":"ls /tmp/openrct2-src/src/openrct2/ride/ 2>/dev/null | head -50","description":"List ride source files"}Angles.h CableLift.cpp CableLift.h CarEntry.cpp CarEntry.h MazeCost.cpp MazeCost.h Ride.cpp Ride.h RideAudio.cpp RideAudio.h RideBreakdownMap.h RideColour.h RideConstruction.cpp RideConstruction.h RideData.cpp RideData.h RideEntry.h RideManager.cpp RideManager.hpp RideRatings.cpp RideRatings.h RideStringIds.h RideTypes.h ShopItem.cpp ShopItem.h Station.cpp Station.h Track.cpp Track.h TrackData.cpp TrackData.h TrackDesign.cpp TrackDesign.h TrackDesignRepository.cpp TrackDesignRepository.h TrackDesignSave.cpp TrackIteration.cpp TrackIteration.h TrackPaint.cpp TrackPaint.h TrackStyle.cpp TrackStyle.h TrainManager.cpp TrainManager.h Vehicle.Animation.cpp Vehicle.BoatHire.cpp Vehicle.Collision.cpp Vehicle.Crash.cpp Vehicle.Dodgems.cpp
{"description":"Analyze RCT2 excitement rating math","prompt":"Read /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp (and RideData.cpp, Ride.h as needed) and tell me EXACTLY how excitement/intensity/nausea are computed for RIDE_TYPE_TWISTER_ROLLER_COASTER (ride type 51, the \"steel twister\"). I need actionable numbers to maximize excitement.\n\nSpecifically report:\n1. The RideRatingsCalculateTwisterRollerCoaster function body in full detail, including base ratings, the RideRatingsApplyX helper calls with their exact constants and thresholds.\n2. How each of these sub-scores is computed and what values maximize them: ride_ratings_apply_length, _apply_drops (num drops + highest drop height), _apply_max_speed, _apply_average_speed, _apply_duration, _apply_gforces (max vertical/lateral G, total air time), _apply_turns, _apply_inversions, _apply_proximity, _apply_scenery, _apply_sheltered_ratings (num sheltered sections).\n3. The exact penalty functions at the end (e.g. RideRatingsApplyIntensityPenalty, RideRatingsApplyAdjustments) and how station length / num stations / block brakes affect it.\n4. Anything that PENALIZES excitement: highest drop height too low, too few drops, unfi… (1976 chars)Async agent launched successfully. (This tool result is internal metadata — never quote or paste any part of it, including the agentId below, into a user-facing reply.) agentId: a3f707e856081810f (internal ID - do not mention to user. Use SendMessage with to: 'a3f707e856081810f', summary: '<5-10 word recap>' to continue this agent.) The agent is working in the background. You will be notified automatically when it completes. You know nothing about its results until that notification arrives — do not report, assume, or predict them; continue other work or respond to the user in the meantime. Do not duplicate this agent's work — avoid working with the same files or topics it is using. output_file: /tmp/claude-1001/-workspace/fd1d3240-8c32-4fa3-aab2-0d24ebb28c38/tasks/a3f707e856081810f.output Do NOT Read or tail this file via the shell tool — it is the full subagent JSONL transcript and reading it will overflow your context. If the user asks for progress, say the agent is still running; you'll get a completion notification.
{"dir":0}{"deltas":[{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":0,"piece":"flat","slope_out":0},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":0,"piece":"end_station","slope_out":0},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":0,"piece":"begin_station","slope_out":0},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":0,"piece":"middle_station","slope_out":0},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":16,"piece":"up_25","slope_out":2},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":64,"piece":"up_60","slope_out":4},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":8,"piece":"flat_to_up_25","slope_out":2},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":32,"piece":"up_25_to_up_60","slope_out":4},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":32,"piece":"up_60_to_up_25","slope_out":2},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":8,"piece":"up_25_to_flat","slope_out":0},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":-16,"piece":"down_25","slope_out":6},{"bank_out":0,"dir_out":0,"dx_tiles":-1,"dy_tiles":0,"dz":-64,"piece":"down_60","slope_out":8},{"bank_out":0,"dir_out":0,"dx… (7397 chars)
I'll start by locating and reading the relevant files.
{"command":"ls /tmp/openrct2-src/src/openrct2/ride/ && wc -l /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp /tmp/openrct2-src/src/openrct2/ride/RideRatings.h","description":"List ride dir and count lines"}Angles.h CableLift.cpp CableLift.h CarEntry.cpp CarEntry.h MazeCost.cpp MazeCost.h Ride.cpp Ride.h RideAudio.cpp RideAudio.h RideBreakdownMap.h RideColour.h RideConstruction.cpp RideConstruction.h RideData.cpp RideData.h RideEntry.h RideManager.cpp RideManager.hpp RideRatings.cpp RideRatings.h RideStringIds.h RideTypes.h ShopItem.cpp ShopItem.h Station.cpp Station.h Track.cpp Track.h TrackData.cpp TrackData.h TrackDesign.cpp TrackDesign.h TrackDesignRepository.cpp TrackDesignRepository.h TrackDesignSave.cpp TrackIteration.cpp TrackIteration.h TrackPaint.cpp TrackPaint.h TrackStyle.cpp TrackStyle.h TrainManager.cpp TrainManager.h Vehicle.Animation.cpp Vehicle.BoatHire.cpp Vehicle.Collision.cpp Vehicle.Crash.cpp Vehicle.Dodgems.cpp Vehicle.MiniGolf.cpp Vehicle.SceneryDoors.cpp Vehicle.Sound.cpp Vehicle.Station.cpp Vehicle.TrackMotion.cpp Vehicle.cpp Vehicle.h VehicleColour.h VehicleData.cpp VehicleData.h VehicleGeometry.cpp VehicleGeometry.h VehicleRiderControl.cpp VehicleSubpositionData.cpp VehicleSubpositionData.h rtd ted 2267 /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp 81 /tmp/openrct2-src/src/openrct2/ride/RideRatings.h 2348 total
{"-n":true,"output_mode":"content","path":"/tmp/openrct2-src/src/openrct2/ride","pattern":"TwisterRollerCoaster"}/tmp/openrct2-src/src/openrct2/ride/RideData.cpp:37:#include "rtd/coaster/ClassicWoodenTwisterRollerCoaster.h" /tmp/openrct2-src/src/openrct2/ride/RideData.cpp:69:#include "rtd/coaster/TwisterRollerCoaster.h" /tmp/openrct2-src/src/openrct2/ride/RideData.cpp:309: /* RIDE_TYPE_TWISTER_ROLLER_COASTER */ TwisterRollerCoasterRTD, /tmp/openrct2-src/src/openrct2/ride/RideData.cpp:360: /* RIDE_TYPE_CLASSIC_WOODEN_TWISTER_ROLLER_COASTER */ ClassicWoodenTwisterRollerCoasterRTD, /tmp/openrct2-src/src/openrct2/ride/TrackStyle.cpp:31: GetTrackPaintFunctionClassicWoodenTwisterRC, // classicWoodenTwisterRollerCoaster /tmp/openrct2-src/src/openrct2/ride/rtd/coaster/TwisterRollerCoaster.h:20:constexpr RideTypeDescriptor TwisterRollerCoasterRTD = /tmp/openrct2-src/src/openrct2/ride/rtd/coaster/ClassicWoodenTwisterRollerCoaster.h:19:constexpr RideTypeDescriptor ClassicWoodenTwisterRollerCoasterRTD = /tmp/openrct2-src/src/openrct2/ride/rtd/coaster/ClassicWoodenTwisterRollerCoaster.h:24: .trackStyle = TrackStyle::classicWoodenTwisterRollerCoaster, /tmp/openrct2-src/src/openrct2/ride/TrackStyle.h:28: classicWoodenTwisterRollerCoaster,
{"file_path":"/tmp/openrct2-src/src/openrct2/ride/rtd/coaster/TwisterRollerCoaster.h"}1 /*****************************************************************************
2 * Copyright (c) 2014-2026 OpenRCT2 developers
3 *
4 * For a complete list of all authors, please refer to contributors.md
5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6 *
7 * OpenRCT2 is licensed under the GNU General Public License version 3.
8 *****************************************************************************/
9
10 #pragma once
11
12 #include "../../../SpriteIds.h"
13 #include "../../../paint/support/MetalSupports.h"
14 #include "../../RideData.h"
15 #include "../../ShopItem.h"
16
17 // clang-format off
18 namespace OpenRCT2
19 {
20 constexpr RideTypeDescriptor TwisterRollerCoasterRTD =
21 {
22 .Category = RideCategory::rollerCoaster,
23 .StartTrackPiece = TrackElemType::endStation,
24 .TrackPaintFunctions = TrackDrawerDescriptor({
25 .trackStyle = TrackStyle::twisterRollerCoaster,
26 .supportType = MetalSupportType::tubes,
27 .enabledTrackGroups = { TrackGroup::flat, TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::verticalLoop, TrackGroup::slope, Track… (6885 chars)
{"-n":true,"output_mode":"content","path":"/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp","pattern":"Twister"}No matches found
{"command":"grep -n \"^\\(static \\)\\?[A-Za-z_].*(\" /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp | head -120","description":"List function definitions"}97:static void ride_ratings_update_state(RideRating::UpdateState& state); 98:static void ride_ratings_update_state_0(RideRating::UpdateState& state); 99:static void ride_ratings_update_state_1(RideRating::UpdateState& state); 100:static void ride_ratings_update_state_2(RideRating::UpdateState& state); 101:static void ride_ratings_update_state_3(RideRating::UpdateState& state); 102:static void ride_ratings_update_state_4(RideRating::UpdateState& state); 103:static void ride_ratings_update_state_5(RideRating::UpdateState& state); 104:static void ride_ratings_begin_proximity_loop(RideRating::UpdateState& state); 105:static void RideRatingsCalculate(RideRating::UpdateState& state, Ride& ride); 106:static void RideRatingsCalculateValue(Ride& ride); 107:static void ride_ratings_score_close_proximity(RideRating::UpdateState& state, TileElement* inputTileElement); 108:static void RideRatingsAdd(RideRating::Tuple& ratings, int32_t excitement, int32_t intensity, int32_t nausea); 110:static ShelteredEights GetNumOfShelteredEighths(const Ride& ride); 111:static money64 RideComputeUpkeep(RideRating::UpdateState& state, const Ride& ride); 112:static void SetUnreliabilityFactor(Ride& ride); 114:s… (11766 chars)
{"file_path":"/tmp/openrct2-src/src/openrct2/ride/RideRatings.h"}1 /*****************************************************************************
2 * Copyright (c) 2014-2026 OpenRCT2 developers
3 *
4 * For a complete list of all authors, please refer to contributors.md
5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6 *
7 * OpenRCT2 is licensed under the GNU General Public License version 3.
8 *****************************************************************************/
9
10 #pragma once
11
12 #include "../Identifiers.h"
13 #include "../core/FixedPoint.hpp"
14 #include "../world/Location.hpp"
15
16 #include <array>
17
18 struct Ride;
19
20 namespace OpenRCT2
21 {
22 enum class TrackElemType : uint16_t;
23 using RideRating_t = fixed16_2dp;
24 namespace RideRating
25 {
26 // Convenience function for writing ride ratings. The result is a 16 bit signed
27 // integer. To create the ride rating 3.65 type MakeRideRating(3, 65).
28 constexpr RideRating_t make(int16_t whole, uint8_t fraction)
29 {
30 return MakeFixed2dp<RideRating_t>(whole, fraction);
31 }
32
33 constexpr RideRating_t kUndefined = 0xFFFFu;
34
35 #pragma pack(push, 1)
36
… (2970 chars)
{"file_path":"/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp","limit":480,"offset":876}876 static void RideRatingsCalculate(RideRating::UpdateState& state, Ride& ride)
877 {
878 const auto& rrd = ride.getRideTypeDescriptor().RatingsData;
879
880 switch (rrd.Type)
881 {
882 case RatingsCalculationType::Normal:
883 if (!ride.flags.has(RideFlag::tested))
884 return;
885 break;
886 case RatingsCalculationType::FlatRide:
887 ride.flags.set(RideFlag::tested, RideFlag::noRawStats);
888 break;
889 case RatingsCalculationType::Stall:
890 ride.upkeepCost = RideComputeUpkeep(state, ride);
891 ride.windowInvalidateFlags.set(RideInvalidateFlag::income);
892 // Exit ratings
893 return;
894 }
895
896 ride.unreliabilityFactor = rrd.Unreliability;
897 SetUnreliabilityFactor(ride);
898
899 const auto shelteredEighths = GetNumOfShelteredEighths(ride);
900 ride.shelteredEighths = (rrd.RideShelter == kDynamicRideShelterRating) ? shelteredEighths.TotalShelteredEighths
901 : rrd.RideShelter;
902
903 RideRating::Tuple ratings = rrd.BaseRatings;… (21161 chars)
{"file_path":"/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp","limit":660,"offset":1357}1357 static uint32_t get_proximity_score_helper_1(uint16_t x, uint16_t max, uint32_t multiplier)
1358 {
1359 return (std::min(x, max) * multiplier) >> 16;
1360 }
1361
1362 static uint32_t get_proximity_score_helper_2(uint16_t x, uint16_t additionIfNotZero, uint16_t max, uint32_t multiplier)
1363 {
1364 uint32_t result = x;
1365 if (result != 0)
1366 result += additionIfNotZero;
1367 return (std::min<int32_t>(result, max) * multiplier) >> 16;
1368 }
1369
1370 static uint32_t get_proximity_score_helper_3(uint16_t x, uint16_t resultIfNotZero)
1371 {
1372 return x == 0 ? 0 : resultIfNotZero;
1373 }
1374
1375 /**
1376 *
1377 * rct2: 0x0065E277
1378 */
1379 static uint32_t ride_ratings_get_proximity_score(RideRating::UpdateState& state)
1380 {
1381 const uint16_t* scores = state.ProximityScores;
1382
1383 uint32_t result = 0;
1384 result += get_proximity_score_helper_1(scores[PROXIMITY_WATER_OVER], 60, 0x00AAAA);
1385 result += get_proximity_score_helper_1(scores[PROXIMITY_WATER_TOUCH], 22, 0x0245D1);
1386 result += get_proximity_score_helper_1(scores[PROXIMITY_WATER_LOW], 10, 0x020000);
1387 result += get_proximity_score_helper… (27891 chars)
{"file_path":"/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp","limit":252,"offset":2016}2016 static void RideRatingsApplyBonusReversals(
2017 RideRating::Tuple& ratings, const Ride& ride, RideRating::UpdateState& state, RatingsModifier modifier)
2018 {
2019 int32_t numReversers = std::min<uint16_t>(state.AmountOfReversers, modifier.threshold);
2020 RideRatingsAdd(
2021 ratings, numReversers * modifier.excitement, numReversers * modifier.intensity, numReversers * modifier.nausea);
2022 }
2023
2024 static void RideRatingsApplyBonusHoles(RideRating::Tuple& ratings, const Ride& ride, RatingsModifier modifier)
2025 {
2026 auto bonusHoles = std::min<uint8_t>(modifier.threshold, ride.numHoles);
2027 RideRatingsAdd(ratings, bonusHoles * modifier.excitement, bonusHoles * modifier.intensity, bonusHoles * modifier.nausea);
2028 }
2029
2030 static void RideRatingsApplyBonusNumTrains(RideRating::Tuple& ratings, const Ride& ride, RatingsModifier modifier)
2031 {
2032 // For some reason the original code ran this twice, before and after the operation option bonus
2033 // Has been changed to call once with double value
2034 if (ride.numTrains >= modifier.threshold)
2035 {
2036 RideRatingsAdd(ratings, modifier.excitement, modifier.… (10465 chars)
{"command":"grep -rn \"numDrops\\|highestDropHeight\\|totalAirTime\\|numShelteredSections\\|shelteredLength\\|maxLateralG\\|maxPositiveVerticalG\\|maxNegativeVerticalG\\|numInversions\\|numHelices\" /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp /tmp/openrct2-src/src/openrct2/ride/Ride.cpp /tmp/openrct2-src/src/openrct2/ride/Vehicle.TrackMotion.cpp | head -80","description":"Find drop/airtime/G accumulation"}/tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:437: if (ride.numInversions < Limits::kMaxInversions) /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:438: ride.numInversions++; /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:515: curRide->totalAirTime++; /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:518: if (gForces.verticalG > curRide->maxPositiveVerticalG) /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:519: curRide->maxPositiveVerticalG = gForces.verticalG; /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:521: if (gForces.verticalG < curRide->maxNegativeVerticalG) /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:522: curRide->maxNegativeVerticalG = gForces.verticalG; /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:525: curRide->maxLateralG = std::max(curRide->maxLateralG, static_cast<fixed16_2dp>(gForces.lateralG)); /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:669: if (curZ > curRide->highestDropHeight) /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:671: curRide->highestDropHeight = static_cast<uint8_t>(curZ); /tmp/openrct2-src/src/openrct… (3679 chars)
{"file_path":"/tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp","limit":400,"offset":400}400
401 RideBreakdownAddNewsItem(*curRide);
402
403 curRide->windowInvalidateFlags.set(
404 RideInvalidateFlag::main, RideInvalidateFlag::list, RideInvalidateFlag::maintenance);
405
406 curRide->mechanicStatus = MechanicStatus::calling;
407
408 Vehicle* broken_vehicle = getGameState().entities.GetEntity<Vehicle>(curRide->vehicles[curRide->brokenTrain]);
409 if (broken_vehicle != nullptr)
410 {
411 curRide->inspectionStation = broken_vehicle->current_station;
412 }
413 curRide->breakdownReason = curRide->breakdownReasonPending;
414 }
415 }
416 else
417 {
418 if (vehicle->restraints_position + 20 > 0xFF)
419 {
420 vehicle->restraints_position = 255;
421 continue;
422 }
423 vehicle->restraints_position += 20;
424 }
425 vehicle->invalidate();
426 restraintsOpen = false;
427 }
428
429 return restraintsOpen;
430 }
431
432 void RideUpdateMeasurementsSpecialElements_Default… (15201 chars)
{"command":"grep -rn \"kRideMaxDropsCount\\|kMaxInversions\\|kMaxHelices\\|kMaxShelteredSections\\|kRideMaxNumPoweredLifts\" /tmp/openrct2-src/src/openrct2/ --include=*.h --include=*.cpp | head -20; echo ---; grep -rn \"kRtdFlagsCommonCoaster\\b\" -A15 /tmp/openrct2-src/src/openrct2/ride/RideData.h | head -40","description":"Find limits and coaster flags"}/tmp/openrct2-src/src/openrct2/Limits.h:22: constexpr uint8_t kMaxHelices = std::numeric_limits<uint8_t>::max(); /tmp/openrct2-src/src/openrct2/Limits.h:23: constexpr uint8_t kMaxInversions = std::numeric_limits<uint8_t>::max(); /tmp/openrct2-src/src/openrct2/Limits.h:40: constexpr uint8_t kRideMaxDropsCount = std::numeric_limits<uint8_t>::max(); /tmp/openrct2-src/src/openrct2/Limits.h:41: constexpr uint8_t kRideMaxNumPoweredLiftsCount = std::numeric_limits<uint8_t>::max(); /tmp/openrct2-src/src/openrct2/rct12/Limits.h:43: constexpr uint16_t kMaxInversions = 31; /tmp/openrct2-src/src/openrct2/rct12/Limits.h:45: constexpr uint16_t kMaxHelices = 31; /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:437: if (ride.numInversions < Limits::kMaxInversions) /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:544: if (curRide->numPoweredLifts < Limits::kRideMaxNumPoweredLiftsCount) /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:681: if (curRide->numDrops < Limits::kRideMaxDropsCount) /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:710: if (curRide->numDrops < Limits::kRideMaxDropsCount) /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:… (2502 chars)
{"command":"grep -rn \"ToHumanReadableRideLength\\|getTotalLength\\|getTotalTime\" /tmp/openrct2-src/src/openrct2/ride/Ride.cpp /tmp/openrct2-src/src/openrct2/ride/Ride.h | head -20; echo ---; grep -rn \"IncrementTurnCount\\|GetTurnCount\" -A12 /tmp/openrct2-src/src/openrct2/ride/Ride.cpp | sed -n '1,140p'","description":"Find length/time and turn count funcs"}/tmp/openrct2-src/src/openrct2/ride/Ride.cpp:591:int32_t Ride::getTotalLength() const
/tmp/openrct2-src/src/openrct2/ride/Ride.cpp:599:int32_t Ride::getTotalTime() const
/tmp/openrct2-src/src/openrct2/ride/Ride.h:520: int32_t getTotalLength() const;
/tmp/openrct2-src/src/openrct2/ride/Ride.h:521: int32_t getTotalTime() const;
---
4150:void IncrementTurnCount1Element(Ride& ride, uint8_t type)
4151-{
4152- uint16_t* turn_count;
4153- switch (type)
4154- {
4155- case 0:
4156- turn_count = &ride.turnCountDefault;
4157- break;
4158- case 1:
4159- turn_count = &ride.turnCountBanked;
4160- break;
4161- case 2:
4162- turn_count = &ride.turnCountSloped;
--
4175:void IncrementTurnCount2Elements(Ride& ride, uint8_t type)
4176-{
4177- uint16_t* turn_count;
4178- switch (type)
4179- {
4180- case 0:
4181- turn_count = &ride.turnCountDefault;
4182- break;
4183- case 1:
4184- turn_count = &ride.turnCountBanked;
4185- break;
4186- case 2:
4187- turn_count = &ride.turnCountSloped;
--
4200:void IncrementTurnCount3Elements(Ride&… (3890 chars)
{"command":"grep -rn \"kTurnMask\\|kCurrentTurnCountMask\" /tmp/openrct2-src/src/openrct2/ride/Ride.h /tmp/openrct2-src/src/openrct2/ride/Ride.cpp | head; echo ---; sed -n '585,615p' /tmp/openrct2-src/src/openrct2/ride/Ride.cpp; echo ---; grep -rn \"ToHumanReadableRideLength\" -A6 /tmp/openrct2-src/src/openrct2/ride/Ride.h | head -20; echo ---; grep -rn \"kNumShelteredSectionsMask\\|kRotatingWhileSheltered\\|kBankingWhileSheltered\" /tmp/openrct2-src/src/openrct2/ride/Ride.h; echo ---; sed -n '5510,5535p' /tmp/openrct2-src/src/openrct2/ride/Ride.cpp","description":"Get masks and helpers"}/tmp/openrct2-src/src/openrct2/ride/Ride.h:799:constexpr uint16_t kCurrentTurnCountMask = 0xF800;
/tmp/openrct2-src/src/openrct2/ride/Ride.h:800:constexpr uint16_t kTurnMask1Element = 0x001F;
/tmp/openrct2-src/src/openrct2/ride/Ride.h:801:constexpr uint16_t kTurnMask2Elements = 0x00E0;
/tmp/openrct2-src/src/openrct2/ride/Ride.h:802:constexpr uint16_t kTurnMask3Elements = 0x0700;
/tmp/openrct2-src/src/openrct2/ride/Ride.h:803:constexpr uint16_t kTurnMask4PlusElements = 0xF800;
/tmp/openrct2-src/src/openrct2/ride/Ride.cpp:4167: uint16_t value = (*turn_count & kTurnMask1Element) + 1;
/tmp/openrct2-src/src/openrct2/ride/Ride.cpp:4168: *turn_count &= ~kTurnMask1Element;
/tmp/openrct2-src/src/openrct2/ride/Ride.cpp:4170: if (value > kTurnMask1Element)
/tmp/openrct2-src/src/openrct2/ride/Ride.cpp:4171: value = kTurnMask1Element;
/tmp/openrct2-src/src/openrct2/ride/Ride.cpp:4192: uint16_t value = (*turn_count & kTurnMask2Elements) + 0x20;
---
else
{
ft.Add<StringId>(STR_OPEN);
}
}
int32_t Ride::getTotalLength() const
{
int32_t totalLength = 0;
for (int32_t i = 0; i < numStations; i++)
totalLength += stations[i].SegmentLength;
retu… (2669 chars)
{"command":"grep -rn \"limitAirTimeBonus\" /tmp/openrct2-src/src/openrct2/ --include=*.h --include=*.cpp | head; echo ---; sed -n '4249,4335p' /tmp/openrct2-src/src/openrct2/ride/Ride.cpp","description":"air time flag and turn getters"}/tmp/openrct2-src/src/openrct2/object/RideObject.cpp:670: { "limitAirTimeBonus", RideEntryFlag::limitAirTimeBonus },
/tmp/openrct2-src/src/openrct2/ride/RideEntry.h:60: limitAirTimeBonus,
/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp:1278: if (rideEntry->flags.has(RideEntryFlag::limitAirTimeBonus))
/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp:1298: if (rideEntry->flags.has(RideEntryFlag::limitAirTimeBonus))
---
int32_t GetTurnCount1Element(const Ride& ride, uint8_t type)
{
const uint16_t* turn_count;
switch (type)
{
case 0:
turn_count = &ride.turnCountDefault;
break;
case 1:
turn_count = &ride.turnCountBanked;
break;
case 2:
turn_count = &ride.turnCountSloped;
break;
default:
return 0;
}
return (*turn_count) & kTurnMask1Element;
}
int32_t GetTurnCount2Elements(const Ride& ride, uint8_t type)
{
const uint16_t* turn_count;
switch (type)
{
case 0:
turn_count = &ride.turnCountDefault;
break;
case 1:
turn_count = &ride.turnCountBanked;
… (2387 chars)
{"command":"grep -rn \"ToHumanReadableRideLength\" -A6 /tmp/openrct2-src/src/openrct2/ride/RideTypes.h /tmp/openrct2-src/src/openrct2/ride/*.h /tmp/openrct2-src/src/openrct2/*.h 2>/dev/null | head -20; echo ---; grep -rn \"ToHumanReadableRideLength\" /tmp/openrct2-src/src/openrct2/ -r | head","description":"Find ToHumanReadableRideLength"}--- /tmp/openrct2-src/src/openrct2/core/UnitConversion.cpp:74: int32_t ToHumanReadableRideLength(int32_t rideLength) /tmp/openrct2-src/src/openrct2/core/UnitConversion.h:26: int32_t ToHumanReadableRideLength(int32_t rideLength); /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp:1187: uint32_t totalLength = ToHumanReadableRideLength(ride.getTotalLength()); /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp:1828: ratings, (std::min(ToHumanReadableRideLength(ride.getTotalLength()), modifier.threshold) * modifier.excitement) >> 16, /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp:1932: int32_t lengthFactor = ToHumanReadableRideLength(ride.getTotalLength()); /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp:1940: int32_t lengthFactor = (ToHumanReadableRideLength(ride.getTotalLength()) * 209715) >> 16; /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp:2058: int32_t excitement = (ToHumanReadableRideLength(ride.getTotalLength()) * 32768) >> 16; /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp:2074: int32_t lengthFactor = (ToHumanReadableRideLength(ride.getTotalLength()) * 209715) >> 16; /tmp/openrct2-src/src/openrct2/ride/TrackDesign.cpp:164: … (1435 chars)
{"file_path":"/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp","limit":110,"offset":356}356 static void ride_ratings_update_state_2(RideRating::UpdateState& state)
357 {
358 const RideId rideIndex = state.CurrentRide;
359 auto ride = GetRide(rideIndex);
360 if (ride == nullptr || ride->status == RideStatus::closed || ride->type >= RIDE_TYPE_COUNT)
361 {
362 state.State = RIDE_RATINGS_STATE_FIND_NEXT_RIDE;
363 return;
364 }
365
366 auto loc = state.Proximity;
367 TrackElemType trackType = state.ProximityTrackType;
368
369 TileElement* tileElement = MapGetFirstElementAt(loc);
370 if (tileElement == nullptr)
371 {
372 state.State = RIDE_RATINGS_STATE_FIND_NEXT_RIDE;
373 return;
374 }
375 do
376 {
377 if (tileElement->isGhost())
378 continue;
379 if (tileElement->getType() != TileElementType::track)
380 continue;
381 if (tileElement->getBaseZ() != loc.z)
382 continue;
383 if (tileElement->asTrack()->GetRideIndex() != ride->id)
384 {
385 // Only check that the track belongs to the same ride if ride does not have buildable track
386 if (!ride->getRideTypeDescriptor().flags.has(RtdFlag::hasTr… (3915 chars)
{"command":"sed -n '60,90p' /tmp/openrct2-src/src/openrct2/core/UnitConversion.cpp; echo ---BRAKES---; sed -n '696,800p' /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp","description":"length conversion + proximity scoring"}}
int32_t ToHumanReadableSpeed(int32_t baseSpeed)
{
// Divide this value by 29127 to get the human-readable max speed
// (in RCT2, display_speed = (maxSpeed * 9) >> 18)
return (baseSpeed * 9) >> 18;
}
int32_t ToHumanReadableAirTime(uint16_t airTime)
{
return airTime * 3;
}
int32_t ToHumanReadableRideLength(int32_t rideLength)
{
return rideLength >> 16;
}
} // namespace OpenRCT2
---BRAKES---
static void ride_ratings_score_close_proximity(RideRating::UpdateState& state, TileElement* inputTileElement)
{
if (state.StationFlags & RIDE_RATING_STATION_FLAG_NO_ENTRANCE)
{
return;
}
state.ProximityTotal++;
TileElement* tileElement = MapGetFirstElementAt(state.Proximity);
if (tileElement == nullptr)
return;
do
{
if (tileElement->isGhost())
continue;
int32_t waterHeight;
switch (tileElement->getType())
{
case TileElementType::surface:
state.ProximityBaseHeight = tileElement->baseHeight;
if (tileElement->getBaseZ() == state.Proximity.z)
{
proxim… (5116 chars)
{"command":"grep -n \"AmountOfBrakes\\|amountOfBoosters\" /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp | head; echo ---; grep -c \"normalToInversion\" /tmp/openrct2-src/src/openrct2/ride/TrackData.cpp; grep -n \"normalToInversion\" /tmp/openrct2-src/src/openrct2/ride/TrackData.cpp | head -80","description":"brake counting and inversion flags"}344: state.AmountOfBrakes = 0;
345: state.amountOfBoosters = 0;
869: state.AmountOfBrakes++;
871: state.amountOfBoosters++;
1209: upkeep += 20 * state.AmountOfBrakes;
1212: upkeep += 80 * state.amountOfBoosters;
---
9
7325: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
7338: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
8640: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
8654: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
8773: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
8787: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
8845: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
9479: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
9511: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionTo… (1209 chars)
{"command":"grep -n \"Inversion\" /tmp/openrct2-src/src/openrct2/ride/TrackData.cpp | head -60; echo ---; grep -rn \"normalToInversion\\|inversionToNormal\" /tmp/openrct2-src/src/openrct2/ride/Track.h /tmp/openrct2-src/src/openrct2/ride/TrackData.h | head -20","description":"inversion flags in track data"}7325: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
7338: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
8640: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
8654: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
8773: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
8787: .flags = { TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
8845: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
9479: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
9511: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
---
{"command":"for l in 7325 8640 8773 8845 9479 9511 7338 8654 8787; do echo \"== $l\"; awk -v s=$((l-30)) -v e=$l 'NR>=s&&NR<=e' /tmp/openrct2-src/src/openrct2/ride/TrackData.cpp | grep -n \"TrackElemType::\\|description\\|// \" | tail -3; done","description":"Identify inversion-flagged pieces"}== 7325
25: .description = STR_IN_LINE_TWIST_LEFT,
28: .curveChain = { TrackElemType::leftTwistUpToDown, TrackCurve::none },
30: .mirrorElement = TrackElemType::rightTwistDownToUp,
== 8640
25: .description = STR_BARREL_ROLL_LEFT,
28: .curveChain = { TrackElemType::leftBarrelRollDownToUp, TrackCurve::none },
30: .mirrorElement = TrackElemType::rightBarrelRollUpToDown,
== 8773
18: .mirrorElement = TrackElemType::poweredLift,
25: .description = STR_IN_LINE_TWIST_LEFT,
30: .mirrorElement = TrackElemType::rightFlyerTwistUp,
== 8845
25: .description = STR_QUARTER_LOOP,
28: .curveChain = { TrackElemType::invertedFlatToDown90QuarterLoop, TrackCurve::none },
30: .mirrorElement = TrackElemType::up90ToInvertedFlatQuarterLoop,
== 9479
17: .mirrorElement = TrackElemType::leftQuarterTurn1TileDown90,
25: .description = STR_QUARTER_LOOP,
30: .mirrorElement = TrackElemType::multiDimUp90ToInvertedFlatQuarterLoop,
== 9511
14: .mirrorElement = TrackElemType::multiDimFlatToDown90QuarterLoop,
25: .description = STR_QUARTER_LOOP,
30: .mirrorElement = TrackElemType::multiDimInverte… (1819 chars)
{"dir":0,"ride_type":51,"x":58,"y":60}{"cursor":{"bank":0,"dir":0,"slope":0,"x":58,"y":60,"z":112},"ride_id":0}
{"command":"grep -rn \"enum class TrackElementFlag\" -A 40 /tmp/openrct2-src/src/openrct2/ride/TrackData.h /tmp/openrct2-src/src/openrct2/ride/Track.h 2>/dev/null | head -50","description":"TrackElementFlag enum"}(Bash completed with no output)
{"command":"grep -rn \"normalToInversion\" /tmp/openrct2-src/src/openrct2/ | grep -v TrackData.cpp | head -20","description":"Locate enum definition"}/tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:435: if (ted.flags.has(TrackElementFlag::normalToInversion))
/tmp/openrct2-src/src/openrct2/ride/ted/TED.Corkscrew.h:418: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
/tmp/openrct2-src/src/openrct2/ride/ted/TED.Corkscrew.h:432: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
/tmp/openrct2-src/src/openrct2/ride/ted/TED.Corkscrew.h:476: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
/tmp/openrct2-src/src/openrct2/ride/ted/TED.Corkscrew.h:491: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
/tmp/openrct2-src/src/openrct2/ride/ted/TED.Corkscrew.h:536: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
/tmp/openrct2-src/src/openrct2/ride/ted/TED.Corkscrew.h:553: .flags = { TrackElementFlag::up, TrackElementFlag::normalToInversion, TrackElementFlag::inversionToNormal },
/tmp/openrct2-src/src/open… (3335 chars)
{"pieces":["begin_station","middle_station","middle_station","middle_station","end_station",{"chain":true,"piece":"flat_to_up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25_to_flat"},"flat_to_down_25","down_25_to_down_60","down_60","down_60_to_down_25","down_25_to_flat"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":0,"slope":0,"x":36,"y":60,"z":144},"placed_this_call":22,"total_placed":22}
{"piece":"right_vertical_loop"}'right_vertical_loop' rejected: piece enters at 25-up slope but the track here is flat; add a slope transition piece first (cursor unchanged: {"bank":0,"dir":0,"slope":0,"x":36,"y":60,"z":144})
{"command":"grep -rc \"normalToInversion\" /tmp/openrct2-src/src/openrct2/ride/ted/*.h | grep -v \":0\"; echo \"=== DOWN flag files ===\"; grep -rc \"TrackElementFlag::down\" /tmp/openrct2-src/src/openrct2/ride/ted/*.h | grep -v \":0\"","description":"Inversion and down-flag piece families"}/tmp/openrct2-src/src/openrct2/ride/ted/TED.Corkscrew.h:6 /tmp/openrct2-src/src/openrct2/ride/ted/TED.DiveLoop.h:2 /tmp/openrct2-src/src/openrct2/ride/ted/TED.Heartline.h:2 /tmp/openrct2-src/src/openrct2/ride/ted/TED.Loop.h:13 /tmp/openrct2-src/src/openrct2/ride/ted/TED.ZeroG.h:4 /tmp/openrct2-src/src/openrct2/ride/ted/TrackElementDescriptor.h:2 === DOWN flag files === /tmp/openrct2-src/src/openrct2/ride/ted/TED.Corkscrew.h:6 /tmp/openrct2-src/src/openrct2/ride/ted/TED.DiveLoop.h:2 /tmp/openrct2-src/src/openrct2/ride/ted/TED.LongBase.h:2 /tmp/openrct2-src/src/openrct2/ride/ted/TED.Loop.h:11 /tmp/openrct2-src/src/openrct2/ride/ted/TED.ZeroG.h:4
{"pieces":["flat_to_up_25","right_vertical_loop","down_25_to_flat"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":0,"slope":0,"x":32,"y":61,"z":144},"placed_this_call":3,"total_placed":25}
{"command":"grep -c \"TrackElementFlag::down\" /tmp/openrct2-src/src/openrct2/ride/TrackData.cpp; grep -c \"TrackElementFlag::up\" /tmp/openrct2-src/src/openrct2/ride/TrackData.cpp; echo \"--- sample down pieces ---\"; grep -n \"TrackElementFlag::down\" -B28 /tmp/openrct2-src/src/openrct2/ride/TrackData.cpp | grep \"description = \" | head -60","description":"Count down/up flagged pieces"}94 93 --- sample down pieces --- 7925- .description = STR_ON_RIDE_PHOTO_SECTION, 7961- .description = STR_CABLE_LIFT_HILL, 8074- .description = STR_HOLDING_BRAKE_FOR_DROP, 8809- .description = STR_IN_LINE_TWIST_RIGHT, 8823- .description = STR_QUARTER_LOOP, 8839- .description = STR_QUARTER_LOOP, 8855- .description = STR_QUARTER_LOOP, 8931- .description = STR_TOP_SECTION, 8944- .description = STR_VERTICAL_TRACK, 8956- .description = STR_SLOPE_TO_LEVEL, 9473- .description = STR_QUARTER_LOOP, 9489- .description = STR_QUARTER_LOOP, 10240- .description = STR_BLOCK_BRAKES, 10252- .description = STR_BRAKES, 10343- .description = STR_BRAKES,
{"command":"grep -rn \"highestDropHeight\" /tmp/openrct2-src/src/openrct2/ /tmp/openrct2-src/src/openrct2-ui/ | grep -v \"Vehicle.cpp\\|RideRatings.cpp\" | head -20; echo ---; grep -rn \"kCoordsZStep\\b\" /tmp/openrct2-src/src/openrct2/world/Location.hpp | head -3","description":"Drop height units"}/tmp/openrct2-src/src/openrct2/entity/Guest.cpp:1933: if (ride.highestDropHeight > 66 || ride.ratings.excitement >= RideRating::make(8, 00))
/tmp/openrct2-src/src/openrct2/park/ParkFile.cpp:1598: cs.readWrite(ride.highestDropHeight);
/tmp/openrct2-src/src/openrct2/rct1/RCT1.h:322: uint8_t highestDropHeight; // 0x0C7
/tmp/openrct2-src/src/openrct2/rct1/S4Importer.cpp:1036: dst->highestDropHeight = src->highestDropHeight / 2;
/tmp/openrct2-src/src/openrct2/rct1/T4Importer.cpp:267: td->statistics.highestDropHeight = td4Base.HighestDropHeight / 2;
/tmp/openrct2-src/src/openrct2/rct2/RCT2.h:203: uint8_t highestDropHeight; // 0x117
/tmp/openrct2-src/src/openrct2/rct2/S6Importer.cpp:880: dst->highestDropHeight = src->highestDropHeight;
/tmp/openrct2-src/src/openrct2/rct2/T6Exporter.cpp:103: tempStream.WriteValue<uint8_t>(_trackDesign.statistics.highestDropHeight);
/tmp/openrct2-src/src/openrct2/rct2/T6Importer.cpp:207: td->statistics.highestDropHeight = td6.HighestDropHeight;
/tmp/openrct2-src/src/openrct2/ride/Ride.h:309: uint8_t highestDropHeight{};
/tmp/openrct2-src/src/openrct2/rid… (2710 chars)
{"command":"grep -rn \"averageSpeed\" /tmp/openrct2-src/src/openrct2-ui/windows/Ride.cpp /tmp/openrct2-src/src/openrct2/ride/Ride.cpp | head","description":"Average speed display"}/tmp/openrct2-src/src/openrct2-ui/windows/Ride.cpp:5994: ft.Add<int32_t>(ToHumanReadableSpeed(ride->averageSpeed));
{"command":"grep -rn \"averageSpeed\\|averageSpeedTestTimeout\" /tmp/openrct2-src/src/openrct2/ | grep -v \"ParkFile\\|S6\\|S4\\|RCT1.h\\|RCT2.h\\|Scripting\\|ScRide\" | head -20","description":"averageSpeed usage"}/tmp/openrct2-src/src/openrct2/rct1/T4Importer.cpp:255: td->statistics.averageSpeed = td4Base.AverageSpeed;
/tmp/openrct2-src/src/openrct2/rct2/T6Exporter.cpp:85: tempStream.WriteValue<int8_t>(_trackDesign.statistics.averageSpeed);
/tmp/openrct2-src/src/openrct2/rct2/T6Importer.cpp:195: td->statistics.averageSpeed = td6.AverageSpeed;
/tmp/openrct2-src/src/openrct2/ride/Ride.h:289: int32_t averageSpeed{};
/tmp/openrct2-src/src/openrct2/ride/Ride.h:291: uint8_t averageSpeedTestTimeout{};
/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp:1855: int32_t avgSpeedMod = ride.averageSpeed >> 16;
/tmp/openrct2-src/src/openrct2/ride/TrackDesign.cpp:163: statistics.averageSpeed = static_cast<int8_t>(ride.averageSpeed / 65536);
/tmp/openrct2-src/src/openrct2/ride/TrackDesign.cpp:581: stream << DS_TAG(statistics.averageSpeed);
/tmp/openrct2-src/src/openrct2/ride/TrackDesign.h:170: int8_t averageSpeed{};
/tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:481: curRide->averageSpeedTestTimeout++;
/tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:482: if (curRide->averageSpeedTestTimeout >= 32)
/tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp:… (1794 chars)
{"file_path":"/tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp","limit":40,"offset":930}930 ride.flags.unset(RideFlag::testInProgress);
931 ride.flags.set(RideFlag::tested);
932 ride.windowInvalidateFlags.set(RideInvalidateFlag::ratings);
933
934 auto rideStations = ride.getStations();
935 for (int32_t i = ride.numStations - 1; i >= 1; i--)
936 {
937 if (rideStations[i - 1].SegmentTime != 0)
938 continue;
939
940 uint16_t oldTime = rideStations[i - 1].SegmentTime;
941 rideStations[i - 1].SegmentTime = rideStations[i].SegmentTime;
942 rideStations[i].SegmentTime = oldTime;
943
944 int32_t oldLength = rideStations[i - 1].SegmentLength;
945 rideStations[i - 1].SegmentLength = rideStations[i].SegmentLength;
946 rideStations[i].SegmentLength = oldLength;
947 }
948
949 uint32_t totalTime = 0;
950 for (uint8_t i = 0; i < ride.numStations; ++i)
951 {
952 totalTime += rideStations[i].SegmentTime;
953 }
954
955 totalTime = std::max(totalTime, 1u);
956 ride.averageSpeed = ride.averageSpeed / totalTime;
957
958 auto* windowMgr = Ui::GetWindowManager();
959 windowMgr->InvalidateByNumber(WindowClass::ride, ride.id.ToUnderlying());
960 }
961
… (1408 chars)
{"pieces":["flat_to_right_bank","banked_right_turn_5","right_bank_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":1,"slope":0,"x":29,"y":71,"z":144},"placed_this_call":9,"total_placed":34}
{"command":"grep -rn \"getTotalTime\\|STR_RIDE_TIME\" /tmp/openrct2-src/src/openrct2-ui/windows/Ride.cpp | head","description":"Ride time display"}3630: format = STR_RIDE_TIME_ENTRY; 6001: // TODO: STR_RIDE_TIME only takes up to 4 stations modify to take more 6010: ft.Add<uint16_t>(STR_RIDE_TIME_ENTRY_WITH_SEPARATOR); 6017: ft.Add<uint16_t>(STR_RIDE_TIME_ENTRY); 6023: // sadly, STR_RIDE_TIME_ENTRY_WITH_SEPARATOR are defined with the separator AFTER an entry 6027: ft.Add<uint16_t>(STR_RIDE_TIME_ENTRY); 6035: drawTextEllipsised(rt, screenCoords, 308, STR_RIDE_TIME, ft);
{"piece":"right_corkscrew_up"}{"circuit_closed":false,"cost":2350,"cursor":{"bank":15,"dir":2,"slope":0,"x":31,"y":72,"z":224},"pieces_placed":35,"placed":"right_corkscrew_up"}
{"cursor":{"bank":15,"dir":2,"slope":0,"x":31,"y":72,"z":224},"valid_pieces":["left_corkscrew_down","right_corkscrew_down"]}
{"command":"grep -rn \"STR_RIDE_TIME_ENTRY\\b\\|STR_RIDE_TIME_ENTRY \" /tmp/openrct2-src/data/language/en-GB.txt 2>/dev/null | head; grep -rn \"RIDE_TIME\" /tmp/openrct2-src/data/language/en-GB.txt | head","description":"Ride time string format"}(Bash completed with no output)
{"command":"ls /tmp/openrct2-src/; grep -rn \"STR_RIDE_TIME_ENTRY\" /tmp/openrct2-src/src/openrct2/localisation/StringIds.h | head -3; sed -n '3620,3640p' /tmp/openrct2-src/src/openrct2-ui/windows/Ride.cpp","description":"Check time formatting"}CMakeLists.txt
CMakeLists_mingw.txt
CMakeSettings.json
CODE_OF_CONDUCT.md
CONTRIBUTING.md
CommunityGuidelines.md
OpenRCT2.entitlements
PRIVACY.md
assets.json
cmake
contributors.md
data
debian
distribution
docs
emscripten
licence.txt
openrct2.common.props
openrct2.deps.targets
openrct2.proj
openrct2.sln
openrct2.targets
readme.md
resources
scripts
src
test
caption = STR_SPEED;
tooltip = STR_SPEED_TIP;
break;
case RideMode::race:
tweakValue = ride->numLaps;
format = STR_COMMA16;
caption = STR_NUMBER_OF_LAPS;
tooltip = STR_NUMBER_OF_LAPS_TIP;
break;
case RideMode::dodgems:
format = STR_RIDE_TIME_ENTRY;
caption = STR_TIME_LIMIT;
tooltip = STR_TIME_LIMIT_TIP;
break;
case RideMode::swing:
format = STR_COMMA16;
caption = STR_NUMBER_OF_SWINGS;
tooltip = STR_NUMBER_OF_SWINGS_TIP;
break;
case RideMode::rotation:
… (1245 chars)
{"command":"grep -rn \"struct RatingsModifier\" -A 12 /tmp/openrct2-src/src/openrct2/ride/RideData.h; grep -rn \"kDynamicRideShelterRating\\|struct RideRatingsDescriptor\" -A 12 /tmp/openrct2-src/src/openrct2/ride/RideData.h | head -30","description":"RatingsModifier struct"}233:struct RatingsModifier
234-{
235- RatingsModifierType type;
236- int32_t threshold;
237- int32_t excitement;
238- int32_t intensity;
239- int32_t nausea;
240-};
241-
242-constexpr int8_t kDynamicRideShelterRating = -1;
243-
244-struct RideRatingsDescriptor
245-{
242:constexpr int8_t kDynamicRideShelterRating = -1;
243-
244:struct RideRatingsDescriptor
245-{
246- RatingsCalculationType Type;
247- OpenRCT2::RideRating::Tuple BaseRatings;
248- uint8_t Unreliability;
249: // Used for rides with a set sheltered 8ths value (kDynamicRideShelterRating = normal calculation)
250- int8_t RideShelter;
251- bool RelaxRequirementsIfInversions;
252- RatingsModifier Modifiers[32];
253-};
254-
255-struct UpkeepCostsDescriptor
256-{
257- /**
258- * Data about ride running costs. This is widely adjusted by the upkeep
259- * function, so values that don't make much sense here (a roller coaster having
260- * cheaper upkeep than a car ride) are fixed later on.
261- *
{"command":"sed -n '5955,6000p' /tmp/openrct2-src/src/openrct2-ui/windows/Ride.cpp","description":"Ride length display"}stringId = STR_INTENSITY_RATING_RED;
drawText(rt, screenCoords, stringId, ft);
screenCoords.y += kListRowHeight;
// Nausea
ratingName = GetRatingName(ride->ratings.nausea);
ft = Formatter();
ft.Add<uint32_t>(ride->ratings.nausea);
ft.Add<StringId>(ratingName);
stringId = !RideHasRatings(*ride) ? STR_NAUSEA_RATING_NOT_YET_AVAILABLE : STR_NAUSEA_RATING;
drawText(rt, screenCoords, stringId, ft);
screenCoords.y += 2 * kListRowHeight;
// Horizontal rule
Rectangle::fillInset(
rt, { screenCoords - ScreenCoordsXY{ 0, 6 }, screenCoords + ScreenCoordsXY{ 303, -5 } }, colours[1],
Rectangle::BorderStyle::inset);
if (!ride->flags.has(RideFlag::noRawStats))
{
if (ride->getRideTypeDescriptor().specialType == RtdSpecialType::miniGolf)
{
// Holes
ft = Formatter();
… (2234 chars)
{"command":"sed -n '6036,6075p' /tmp/openrct2-src/src/openrct2-ui/windows/Ride.cpp","description":"Ride length display units"}screenCoords.y += kListRowHeight;
}
// Ride length
ft = Formatter();
int32_t numLengths = 0;
// TODO: see above STR_RIDE_LENGTH is also only able to display max 4
for (int32_t i = 0; i < std::min<int32_t>(ride->numStations, 4); i++)
{
StationIndex stationIndex = StationIndex::FromUnderlying(i);
auto length = ride->getStation(stationIndex).SegmentLength;
if (length != 0)
{
length >>= 16;
ft.Add<StringId>(STR_RIDE_LENGTH_ENTRY_WITH_SEPARATOR);
ft.Add<uint16_t>(length & 0xFFFF);
numLengths++;
}
}
if (numLengths == 0)
{
ft.Add<StringId>(STR_RIDE_LENGTH_ENTRY);
ft.Add<uint16_t>(0);
numLengths++;
… (2062 chars)
{"pieces":["left_corkscrew_down","flat","flat_to_right_bank","banked_right_turn_5","right_bank_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25","down_25_to_flat"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":2,"slope":0,"x":43,"y":78,"z":128},"placed_this_call":12,"total_placed":47}
{"pieces":["right_corkscrew_up","left_corkscrew_down"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":2,"slope":0,"x":46,"y":75,"z":128},"placed_this_call":2,"total_placed":49}
{"pieces":["flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat_to_up_25","up_25_to_flat","flat_to_down_25","down_25_to_flat","flat_to_up_25","up_25_to_flat","flat","flat","flat_to_right_bank","right_bank","banked_right_turn_5","right_bank_to_flat"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":3,"slope":0,"x":64,"y":71,"z":144},"placed_this_call":18,"total_placed":67}
{"pieces":["flat_to_down_25","down_25","down_25_to_flat","flat","flat","flat","flat","flat","flat","right_turn_5","brakes","brakes","flat"]}{"circuit_closed":true,"cursor":{"bank":0,"dir":0,"slope":0,"x":58,"y":60,"z":112},"placed_this_call":13,"total_placed":80}
Circuit closed with 80 pieces. Testing now to bank a score.
{"bounds":{"max_tile_x":64,"max_tile_y":78,"max_z":312,"min_tile_x":29,"min_tile_y":60,"min_z":112},"placed_pieces":["begin_station","middle_station","middle_station","middle_station","end_station",{"chain":true,"t":"flat_to_up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25_to_flat"},"flat_to_down_25","down_25_to_down_60","down_60","down_60_to_down_25","down_25_to_flat","flat_to_up_25","right_vertical_loop","down_25_to_flat","flat_to_right_bank","banked_right_turn_5","right_bank_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","right_corkscrew_up","left_corkscrew_down","flat","flat_to_right_bank","banked_right_turn_5","right_bank_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25","down_25_to_flat","right_corkscrew_up","left_corkscrew_down","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat_to_up_25","up_25_to_fla… (2164 chars)
Banked 6.27 excitement. Intensity is only 6.33 — lots of headroom. Let me check the rating math.
{"command":"cd /tmp/openrct2-src && grep -n \"Twister\" src/openrct2/ride/RideRatings.cpp | head -20","description":"Find twister rating function"}Shell cwd was reset to /workspace
{"-A":60,"output_mode":"content","path":"/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp","pattern":"TwisterRollerCoaster"}No matches found
{"command":"grep -rn \"Twister\\|TWISTER\" /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp /tmp/openrct2-src/src/openrct2/ride/RideData.cpp 2>/dev/null | head -20","description":"Grep twister in rating files"}/tmp/openrct2-src/src/openrct2/ride/RideData.cpp:37:#include "rtd/coaster/ClassicWoodenTwisterRollerCoaster.h" /tmp/openrct2-src/src/openrct2/ride/RideData.cpp:42:#include "rtd/coaster/HeartlineTwisterCoaster.h" /tmp/openrct2-src/src/openrct2/ride/RideData.cpp:44:#include "rtd/coaster/HyperTwister.h" /tmp/openrct2-src/src/openrct2/ride/RideData.cpp:69:#include "rtd/coaster/TwisterRollerCoaster.h" /tmp/openrct2-src/src/openrct2/ride/RideData.cpp:309: /* RIDE_TYPE_TWISTER_ROLLER_COASTER */ TwisterRollerCoasterRTD, /tmp/openrct2-src/src/openrct2/ride/RideData.cpp:324: /* RIDE_TYPE_HEARTLINE_TWISTER_COASTER */ HeartlineTwisterCoasterRTD, /tmp/openrct2-src/src/openrct2/ride/RideData.cpp:350: /* RIDE_TYPE_HYPER_TWISTER, */ HyperTwisterRTD, /tmp/openrct2-src/src/openrct2/ride/RideData.cpp:360: /* RIDE_TYPE_CLASSIC_WOODEN_TWISTER_ROLLER_COASTER */ ClassicWoodenTwisterRollerCoasterRTD,
{"command":"sed -n '1,200p' /tmp/openrct2-src/src/openrct2/ride/rtd/coaster/TwisterRollerCoaster.h | grep -n \"Ratings\\|rating\" ","description":"Find ratings calc reference"}36: .OperatingSettings = { 10, 27 },
45: .RatingsMultipliers = { 52, 36, 10 },
64: .RatingsData =
66: RatingsCalculationType::Normal,
72: { RatingsModifierType::BonusLength, 6000, 764, 0, 0 },
73: { RatingsModifierType::BonusSynchronisation, 0, RideRating::make(0, 40), RideRating::make(0, 05), 0 },
74: { RatingsModifierType::BonusTrainLength, 0, 187245, 0, 0 },
75: { RatingsModifierType::BonusMaxSpeed, 0, 44281, 88562, 35424 },
76: { RatingsModifierType::BonusAverageSpeed, 0, 291271, 436906, 0 },
77: { RatingsModifierType::BonusDuration, 150, 26214, 0, 0 },
78: { RatingsModifierType::BonusGForces, 0, 24576, 32768, 49648 },
79: { RatingsModifierType::BonusTurns, 0, 26749, 34767, 45749 },
80: { RatingsModifierType::BonusDrops, 0, 29127, 46811, 49152 },
81: { RatingsModifierType::BonusSheltered, 0, 15420, 32768, 35108 },
82: { Ratings… (1922 chars)
{"command":"sed -n '55,100p' /tmp/openrct2-src/src/openrct2/ride/rtd/coaster/TwisterRollerCoaster.h","description":"Show full ratings data"}{ Drawing::Colour::white, Drawing::Colour::white, Drawing::Colour::lightBlue },
{ Drawing::Colour::darkGreen, Drawing::Colour::mossGreen, Drawing::Colour::darkBrown },
{ Drawing::Colour::bordeauxRed, Drawing::Colour::lightOrange, Drawing::Colour::white },
{ Drawing::Colour::lightBlue, Drawing::Colour::yellow, Drawing::Colour::darkPink }, // Scream
{ Drawing::Colour::darkOrange, Drawing::Colour::darkOrange, Drawing::Colour::black }, // Rougarou
),
.ColourPreview = { SPR_RIDE_DESIGN_PREVIEW_TWISTER_ROLLER_COASTER_TRACK, SPR_RIDE_DESIGN_PREVIEW_TWISTER_ROLLER_COASTER_SUPPORTS },
.ColourKey = RideColourKey::Ride,
.Name = "twister_rc",
.RatingsData =
{
RatingsCalculationType::Normal,
{ RideRating::make(3, 50), RideRating::make(0, 40), RideRating::make(0, 30) },
15,
kDynamicRideShelterRating,
true,
{
{ RatingsModifierType::BonusLength, 6000, 764, 0, 0 },
{ RatingsModifierType::BonusSynchronisation, 0, RideRating::make(0, 40), RideRating::make(0, 05), 0 },
{ RatingsModifierType::BonusTrainLength, 0, … (2692 chars)
{"command":"grep -n \"case RatingsModifierType::Bonus\\|case RatingsModifierType::Requirement\\|case RatingsModifierType::Penalty\" -A 12 /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp | sed -n '1,200p'","description":"Show modifier switch cases"}909: case RatingsModifierType::BonusLength: 910- RideRatingsApplyBonusLength(ratings, ride, modifier); 911- break; 912: case RatingsModifierType::BonusSynchronisation: 913- RideRatingsApplyBonusSynchronisation(ratings, ride, modifier); 914- break; 915: case RatingsModifierType::BonusTrainLength: 916- RideRatingsApplyBonusTrainLength(ratings, ride, modifier); 917- break; 918: case RatingsModifierType::BonusMaxSpeed: 919- RideRatingsApplyBonusMaxSpeed(ratings, ride, modifier); 920- break; 921: case RatingsModifierType::BonusAverageSpeed: 922- RideRatingsApplyBonusAverageSpeed(ratings, ride, modifier); 923- break; 924: case RatingsModifierType::BonusDuration: 925- RideRatingsApplyBonusDuration(ratings, ride, modifier); 926- break; 927: case RatingsModifierType::BonusGForces: 928- RideRatingsApplyBonusGForces(ratings, ride, modifier); 929- break; 930: case RatingsModifierType::BonusTurns: 931-… (7783 chars)
{"command":"grep -n \"static void RideRatingsApplyBonusLength\\|static void RideRatingsApplyBonusMaxSpeed\\|static void RideRatingsApplyBonusAverageSpeed\\|static void RideRatingsApplyBonusDuration\\|static void RideRatingsApplyBonusGForces\\|static void RideRatingsApplyBonusTurns\\|static void RideRatingsApplyBonusDrops\\|static void RideRatingsApplyBonusSheltered\\|static void RideRatingsApplyBonusProximity\\|static void RideRatingsApplyBonusTrainLength\\|static void RideRatingsApplyPenaltyLateralGs\\|static void RideRatingsApplyIntensityPenalty\\|static void RideRatingsApplyAdjustments\" -A 22 /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp","description":"Show bonus function bodies"}114:static void RideRatingsApplyAdjustments(const Ride& ride, RideRating::Tuple& ratings); 115:static void RideRatingsApplyIntensityPenalty(RideRating::Tuple& ratings); 116- 117:static void RideRatingsApplyBonusLength(RideRating::Tuple& ratings, const Ride& ride, RatingsModifier modifier); 118-static void RideRatingsApplyBonusSynchronisation(RideRating::Tuple& ratings, const Ride& ride, RatingsModifier modifier); 119:static void RideRatingsApplyBonusTrainLength(RideRating::Tuple& ratings, const Ride& ride, RatingsModifier modifier); 120:static void RideRatingsApplyBonusMaxSpeed(RideRating::Tuple& ratings, const Ride& ride, RatingsModifier modifier); 121:static void RideRatingsApplyBonusAverageSpeed(RideRating::Tuple& ratings, const Ride& ride, RatingsModifier modifier); 122:static void RideRatingsApplyBonusDuration(RideRating::Tuple& ratings, const Ride& ride, RatingsModifier modifier); 123:static void RideRatingsApplyBonusGForces(RideRating::Tuple& ratings, const Ride& ride, RatingsModifier modifier); 124:static void RideRatingsApplyBonusTurns(RideRating::Tuple& ratings, const Ride& ride, RatingsModifier modifier); 125:static void RideRatingsApplyBonusDrops(RideRating::Tuple& rati… (14364 chars)
{"file_path":"/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp","limit":22,"offset":855}855 } 856 break; 857 } 858 default: 859 break; 860 } // switch tileElement->getType 861 } while (!(tileElement++)->isLastForTile()); 862 863 uint8_t direction = inputTileElement->getDirection(); 864 ride_ratings_score_close_proximity_in_direction(state, inputTileElement, (direction + 1) & 3); 865 ride_ratings_score_close_proximity_in_direction(state, inputTileElement, (direction - 1) & 3); 866 ride_ratings_score_close_proximity_loops(state, inputTileElement); 867 868 if (trackTypeIsBrakes(state.ProximityTrackType)) 869 state.AmountOfBrakes++; 870 else if (trackTypeIsBooster(state.ProximityTrackType)) 871 state.amountOfBoosters++; 872 else if (trackTypeIsReverser(state.ProximityTrackType)) 873 state.AmountOfReversers++; 874 } 875 876 static void RideRatingsCalculate(RideRating::UpdateState& state, Ride& ride)
{"command":"grep -n \"ride_ratings_get_gforce_ratings\\|ride_ratings_get_turns_ratings\\|ride_ratings_get_drop_ratings\\|ride_ratings_get_sheltered_ratings\\|ride_ratings_get_excessive_lateral_g_penalty\\|ToHumanReadableRideLength\" -A 60 /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp | sed -n '1,240p'","description":"Show subrating functions"}1187: uint32_t totalLength = ToHumanReadableRideLength(ride.getTotalLength());
1188-
1189- // The data originally here was 20's and 0's. The 20's all represented
1190- // rides that had tracks. The 0's were fixed rides like crooked house or
1191- // dodgems.
1192- // Data source is 0x0097E3AC
1193- totalLength *= ride.getRideTypeDescriptor().UpkeepCosts.TrackLengthMultiplier;
1194- upkeep += static_cast<uint16_t>(totalLength >> 10);
1195-
1196- if (ride.flags.has(RideFlag::onRidePhoto))
1197- {
1198- // The original code read from a table starting at 0x0097E3AE and
1199- // incrementing by 0x12 bytes between values. However, all of these
1200- // values were 40. I have replaced the table lookup with the constant
1201- // 40 in this case.
1202- upkeep += 40;
1203- }
1204-
1205- // Add maintenance cost for reverser track pieces
1206- upkeep += 10 * state.AmountOfReversers;
1207-
1208- // Add maintenance cost for brake track pieces
1209- upkeep += 20 * state.AmountOfBrakes;
1210-
1211- // Add maintenance cost for booster track pieces
1212- upkeep += 80 * state.amountOfBoosters;
1213-
1214- // these s… (9075 chars)
{"command":"grep -n \"getInversionsRatings\\|GetSpecialTrackElementsRating\\|get_flat_turns_rating\\|get_banked_turns_rating\\|get_sloped_turns_rating\\|ride_ratings_get_excessive_lateral_g_penalty\" -A 55 /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp | sed -n '1,230p'","description":"Show turn and inversion rating funcs"}1445:static RideRating::Tuple get_flat_turns_rating(const Ride& ride)
1446-{
1447- int32_t num3PlusTurns = GetTurnCount3Elements(ride, 0);
1448- int32_t num2Turns = GetTurnCount2Elements(ride, 0);
1449- int32_t num1Turns = GetTurnCount1Element(ride, 0);
1450-
1451- RideRating::Tuple rating;
1452- rating.excitement = (num3PlusTurns * 0x28000) >> 16;
1453- rating.excitement += (num2Turns * 0x30000) >> 16;
1454- rating.excitement += (num1Turns * 63421) >> 16;
1455-
1456- rating.intensity = (num3PlusTurns * 81920) >> 16;
1457- rating.intensity += (num2Turns * 49152) >> 16;
1458- rating.intensity += (num1Turns * 21140) >> 16;
1459-
1460- rating.nausea = (num3PlusTurns * 0x50000) >> 16;
1461- rating.nausea += (num2Turns * 0x32000) >> 16;
1462- rating.nausea += (num1Turns * 42281) >> 16;
1463-
1464- return rating;
1465-}
1466-
1467-/**
1468- *
1469- * rct2: 0x0065DF72
1470- */
1471:static RideRating::Tuple get_banked_turns_rating(const Ride& ride)
1472-{
1473- int32_t num3PlusTurns = GetTurnCount3Elements(ride, 1);
1474- int32_t num2Turns = GetTurnCount2Elements(ride, 1);
1475- int32_t num1Turns = GetTurnCount1Element(ride, 1);
1476-
147… (8361 chars)
{"command":"grep -n \"GetTurnCount3Elements\\|GetTurnCount2Elements\\|GetTurnCount1Element\\|GetTurnCount4PlusElements\\|IncrementTurnCount\\|turnCount\" -B2 -A 30 /tmp/openrct2-src/src/openrct2/ride/Ride.h | head -80; echo ===; grep -rn \"ride_ratings_get_excessive_lateral_g_penalty\" -A 30 /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp","description":"Turn counting and lateral penalty"}300- TileCoordsXYZ curTestTrackLocation;
301- // Next 3 variables are related (XXXX XYYY ZZZa aaaa)
302: uint16_t turnCountDefault{}; // X = current turn count
303: uint16_t turnCountBanked{};
304: uint16_t turnCountSloped{}; // X = number turns > 3 elements
305- // Y is number of powered lifts, X is drops
306- uint8_t numDrops{};
307- uint8_t numPoweredLifts{};
308- uint8_t startDropHeight{};
309- uint8_t highestDropHeight{};
310- int32_t shelteredLength{};
311- // Unused always 0? Should affect nausea
312- uint16_t var11C{};
313- uint8_t numShelteredSections{}; // (?abY YYYY)
314- // Customer counter in the current 960 game tick (about 30 seconds) interval
315- uint16_t curNumCustomers{};
316- // Counts ticks to update customer intervals, resets each 960 game ticks.
317- uint16_t numCustomersTimeout{};
318- // Customer count in the last 10 * 960 game ticks (sliding window)
319- uint16_t numCustomers[OpenRCT2::Limits::kCustomerHistorySize]{};
320- money64 price[OpenRCT2::RCT2::ObjectLimits::kMaxShopItemsPerRideEntry]{};
321- TileCoordsXYZ chairliftBullwheelLocation[2];
322- OpenRCT2::RideRating::Tuple ratings{};
… (5553 chars)
{"command":"grep -rn \"IncrementTurnCount4PlusElements\\|IncrementTurnCount3Elements\\|numDrops++\\|numDrops +=\\|highestDropHeight\" /tmp/openrct2-src/src/openrct2/ --include=*.cpp | head -20","description":"Find turn/drop measurement code"}/tmp/openrct2-src/src/openrct2/entity/Guest.cpp:1933: if (ride.highestDropHeight > 66 || ride.ratings.excitement >= RideRating::make(8, 00)) /tmp/openrct2-src/src/openrct2/park/ParkFile.cpp:1598: cs.readWrite(ride.highestDropHeight); /tmp/openrct2-src/src/openrct2/rct1/S4Importer.cpp:1036: dst->highestDropHeight = src->highestDropHeight / 2; /tmp/openrct2-src/src/openrct2/rct1/T4Importer.cpp:267: td->statistics.highestDropHeight = td4Base.HighestDropHeight / 2; /tmp/openrct2-src/src/openrct2/rct2/S6Importer.cpp:880: dst->highestDropHeight = src->highestDropHeight; /tmp/openrct2-src/src/openrct2/rct2/T6Exporter.cpp:103: tempStream.WriteValue<uint8_t>(_trackDesign.statistics.highestDropHeight); /tmp/openrct2-src/src/openrct2/rct2/T6Importer.cpp:207: td->statistics.highestDropHeight = td6.HighestDropHeight; /tmp/openrct2-src/src/openrct2/ride/Ride.cpp:4200:void IncrementTurnCount3Elements(Ride& ride, uint8_t type) /tmp/openrct2-src/src/openrct2/ride/Ride.cpp:4225:void IncrementTurnCount4PlusElements(Ride& ride, uint8_t type) /tmp/openrct2-src/src/openrct2/ride/Ride.cpp:4233: IncrementTurnCo… (2414 chars)
{"command":"sed -n '560,720p' /tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp","description":"Read measurement update code"}break;
case TrackElemType::spinningTunnel:
curRide->specialTrackElements.set(SpecialElement::spinningTunnel);
break;
case TrackElemType::waterfall:
curRide->specialTrackElements.set(SpecialElement::waterfall);
break;
case TrackElemType::logFlumeReverser:
curRide->specialTrackElements.set(SpecialElement::reverser);
break;
case TrackElemType::whirlpool:
curRide->specialTrackElements.set(SpecialElement::whirlpool);
break;
case TrackElemType::waterSplash:
if (velocity >= 11.0_mph)
{
curRide->specialTrackElements.set(SpecialElement::splash);
}
break;
default:
break;
}
const auto& ted = GetTrackElementDescriptor(trackElemType);
auto testingFlags = curRide->testingFlags;
if (testingFlags.has(RideTestingFlag::turnLeft) && ted.flags.has(TrackElementFlag::turnLeft))
{
// 0x800 as this is masked to kCurrentTurnCountMask
curRide->turnC… (6067 chars)
{"command":"sed -n '1258,1320p' /tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp; echo \"=== turncount ===\"; sed -n '4180,4270p' /tmp/openrct2-src/src/openrct2/ride/Ride.cpp; echo \"=== len/time ===\"; grep -rn \"ToHumanReadableRideLength\\|getTotalTime\\|getTotalLength\" /tmp/openrct2-src/src/openrct2/ride/Ride.cpp /tmp/openrct2-src/src/openrct2/ride/Ride.h | head","description":"Air time adjustment and turn counts"}static void RideRatingsApplyAdjustments(const Ride& ride, RideRating::Tuple& ratings)
{
const auto* rideEntry = GetRideEntryByIndex(ride.subtype);
if (rideEntry == nullptr)
{
return;
}
// Apply ride entry multipliers
RideRatingsAdd(
ratings, ((static_cast<int32_t>(ratings.excitement) * rideEntry->excitement_multiplier) >> 7),
((static_cast<int32_t>(ratings.intensity) * rideEntry->intensity_multiplier) >> 7),
((static_cast<int32_t>(ratings.nausea) * rideEntry->nausea_multiplier) >> 7));
// Apply total air time
#ifdef ORIGINAL_RATINGS
if (ride.getRideTypeDescriptor().flags.has(RtdFlag::hasAirTime))
{
uint16_t totalAirTime = ride.totalAirTime;
if (rideEntry->flags.has(RideEntryFlag::limitAirTimeBonus))
{
if (totalAirTime >= 96)
{
totalAirTime -= 96;
ratings.excitement -= totalAirTime / 8;
ratings.nausea += totalAirTime / 16;
}
}
else
{
ratings.excitement += totalAirTime / 8;
ratings.nausea += totalAirTime / 16;
}
}
#else
if (ride.getRideTypeDescr… (4680 chars)
## Key structural finding first There is **no** `RideRatingsCalculateTwisterRollerCoaster` function in this build. OpenRCT2 replaced the per-ride C functions with a **data-driven table** in the ride type descriptor. The twister's entire ratings formula lives in: - `/tmp/openrct2-src/src/openrct2/ride/rtd/coaster/TwisterRollerCoaster.h` (the data) - `/tmp/openrct2-src/src/openrct2/ride/RideRatings.cpp` (the generic evaluator + all `RideRatingsApplyX` helpers) - `/tmp/openrct2-src/src/openrct2/ride/Vehicle.cpp` lines 432–765 (`Vehicle::UpdateMeasurements` — where drops, air time, G, turns, sheltered sections are actually *measured* during the test run) - `/tmp/openrct2-src/src/openrct2/ride/Ride.cpp` lines 4150–4325 (turn counters), 591–605 (total length/time) All ratings are `fixed16_2dp`: **1 point = 0.01 rating**. `RideRating::make(3,50)` = 350 = 3.50. --- ## 1. The twister "function body" (the RatingsData table) `/tmp/openrct2-src/src/openrct2/ride/rtd/coaster/TwisterRollerCoaster.h:64-91` ``` RatingsCalculationType::Normal, BaseRatings = { 3.50 excitement, 0.40 intensity, 0.30 nausea }, Unreliability = 15, RideShelter = kDynamicRideShelterRating (-1, computed from track), RelaxRequirementsIfInversions = true, // <<< HUGE, see §4 Modifiers[] = { // {type, threshold, excitementMul, intensityMul, nauseaMul} { BonusLength, 6000, 764, 0, 0 }, { BonusSynchronisation, 0, 0.40, 0.05, 0 }, { BonusTrainLength, 0, 187245, 0, 0 }, { BonusMaxSpeed, 0, 44281, 88562, 35424 }, { BonusAverageSpeed, 0, 291271, 436906, 0 }, { BonusDuration, 150, 26214, 0, 0 }, { BonusGForces, 0, 24576, 32768, 49648 }, { BonusTurns, 0, 26749, 34767, 45749 }, { BonusDrops, 0, 29127, 46811, 49152 }, { BonusSheltered, 0, 15420, 32768, 35108 }, { BonusReversedTrains, 0, 2, 12, 20 }, { BonusProximity, 0, 20130, 0, 0 }, { BonusScenery, 0, 6693, 0, 0 }, { RequirementDropHeight, 12, 2, 2, 2 }, { RequirementMaxSpeed, 0xA0000, 2, 2, 2 }, { RequirementNegativeGs, 0.40, 2, 2, 2 }, { RequirementNumDrops, 2, 2, 2, 2 }, { PenaltyLateralGs, 0, 24576, 32768, 49648 }, } ``` Also relevant: `.RatingsMultipliers = { 52, 36, 10 }` (ride *value*, not rating), `.BonusValue = 120`, `.Heights = { 40, 24, 8, 9 }` (max track height 40). The multipliers are `Q0.16` fixed point: the applied value is `(subRating * mul) >> 16`. Decimal weights for the twister: | Bonus | E weight | I weight | N weight | |---|---|---|---| | GForces | 0.3750 | 0.5000 | 0.7576 | | Turns (incl. inversions/helices) | 0.4081 | 0.5305 | 0.6980 | | Drops | 0.4444 | 0.7143 | 0.7500 | | Sheltered | 0.2353 | 0.5000 | 0.5357 | | Proximity | 0.3072 | – | – | | Scenery | 0.1021 | – | – | Evaluator: `RideRatingsCalculate()` at `RideRatings.cpp:876`. It starts from `BaseRatings`, loops over `Modifiers` **in table order**, then calls `RideRatingsApplyIntensityPenalty()` and `RideRatingsApplyAdjustments()` (lines 1050–1051). --- ## 2. Every sub-score, exact math, and what maximises it ### `BonusLength` — `RideRatings.cpp:1825` ```cpp E += (min(ToHumanReadableRideLength(ride.getTotalLength()), 6000) * 764) >> 16; ``` `ToHumanReadableRideLength(x) = x >> 16` (metres). **E = 0.011658 pts per metre**, cap 6000 m → max +0.70 E. Zero intensity/nausea — **free excitement, build long track**. 1000 m ≈ +0.12 E. ### `BonusDrops` — `ride_ratings_get_drop_ratings()` `RideRatings.cpp:1721` ```cpp E_sub = (min(9, numDrops) * 728177) >> 16; // 11.111 per drop, HARD CAP AT 9 I_sub = (numDrops * 928426) >> 16; // 14.167 per drop, NO CAP N_sub = (numDrops * 655360) >> 16; // 10.000 per drop, NO CAP E_sub += (highestDropHeight*2 * 16000) >> 16; // 0.4883 per… (25725 chars)
Now I understand the rating math. Key levers: **sloped turns (zero intensity cost)**, **6 inversions (capped)**, **turn variety**, **duration**, **air time**. Rebuilding.
{"demolished":0}
Rating math confirmed: duration≥150, sloped turns, 6 inversions, and proximity are the big free levers. Building v2 fast.
{"dir":0,"ride_type":51,"x":62,"y":60}{"cursor":{"bank":0,"dir":0,"slope":0,"x":62,"y":60,"z":112},"ride_id":0}
{"pieces":["begin_station","middle_station","middle_station","middle_station","end_station",{"chain":true,"piece":"flat_to_up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25_to_flat"},"flat_to_down_25","right_turn_3_down_25","right_turn_3_down_25","right_turn_3_down_25","right_turn_3_down_25","down_25","down_25_to_down_60","down_60_to_down_25","down_25_to_flat"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":0,"slope":0,"x":37,"y":60,"z":112},"placed_this_call":29,"total_placed":29}
{"pieces":["half_loop_up","half_loop_down"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":0,"slope":0,"x":37,"y":60,"z":112},"placed_this_call":0,"rejection":{"error":"piece enters at 25-up slope but the track here is flat; add a slope transition piece first","index":0,"piece":"half_loop_up"},"total_placed":29}
{"pieces":["flat_to_up_25","half_loop_up","half_loop_down","down_25_to_flat","flat_to_up_25","right_vertical_loop","down_25_to_flat"]}{"circuit_closed":false,"cursor":{"bank":15,"dir":2,"slope":0,"x":36,"y":60,"z":272},"placed_this_call":2,"rejection":{"error":"Twister Roller Coaster 1 in the way","index":2,"piece":"half_loop_down"},"total_placed":31}
{"cursor":{"bank":15,"dir":2,"slope":0,"x":36,"y":60,"z":272},"valid_pieces":["left_corkscrew_down","right_corkscrew_down"]}
{"pieces":["right_corkscrew_down","flat_to_down_25","down_25","down_25","down_25","down_25","down_25_to_flat","flat_to_up_25","right_vertical_loop","down_25_to_flat","right_corkscrew_up","left_corkscrew_down","right_corkscrew_up","left_corkscrew_down","flat_to_left_bank","banked_left_turn_5","left_bank_to_flat"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":2,"slope":0,"x":34,"y":39,"z":112},"placed_this_call":17,"total_placed":48}
{"pieces":["flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat","flat","flat","flat","flat","flat","left_turn_5"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":1,"slope":0,"x":66,"y":42,"z":112},"placed_this_call":31,"total_placed":79}
{"pieces":["flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat","flat","flat","flat","left_turn_5","flat"]}{"circuit_closed":true,"cursor":{"bank":0,"dir":0,"slope":0,"x":62,"y":60,"z":112},"placed_this_call":18,"total_placed":97}
{"bounds":{"max_tile_x":66,"max_tile_y":63,"max_z":360,"min_tile_x":30,"min_tile_y":39,"min_z":112},"placed_pieces":["begin_station","middle_station","middle_station","middle_station","end_station",{"chain":true,"t":"flat_to_up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25_to_flat"},"flat_to_down_25","right_turn_3_down_25","right_turn_3_down_25","right_turn_3_down_25","right_turn_3_down_25","down_25","down_25_to_down_60","down_60_to_down_25","down_25_to_flat","flat_to_up_25","half_loop_up","right_corkscrew_down","flat_to_down_25","down_25","down_25","down_25","down_25","down_25_to_flat","flat_to_up_25","right_vertical_loop","down_25_to_flat","right_corkscrew_up","left_corkscrew_down","right_corkscrew_up","left_corkscrew_down","flat_to_left_bank","banked_left_turn_5","left_bank_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25",… (2438 chars)
Intensity 14.86 wrecked it (lateral G 3.11 crossed the catastrophic threshold). Rebuilding with banked turns and a lower lift.
{"demolished":0}
{"dir":0,"ride_type":51,"x":62,"y":60}{"cursor":{"bank":0,"dir":0,"slope":0,"x":62,"y":60,"z":112},"ride_id":0}
{"pieces":["begin_station","middle_station","middle_station","middle_station","end_station",{"chain":true,"piece":"flat_to_up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25"},{"chain":true,"piece":"up_25_to_flat"},"flat_to_down_25","right_turn_3_down_25","right_turn_3_down_25","right_turn_3_down_25","right_turn_3_down_25","down_25","down_25","down_25","down_25","down_25_to_flat","flat_to_up_25","half_loop_up","right_corkscrew_down","flat_to_down_25","down_25","down_25","down_25","down_25","down_25_to_flat","flat_to_up_25","right_vertical_loop","down_25_to_flat","right_corkscrew_up","left_corkscrew_down","right_corkscrew_up","left_corkscrew_down","flat_to_left_bank","banked_left_turn_5","left_bank_to_flat"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":2,"slope":0,"x":34,"y":39,"z":112},"placed_this_call":48,"total_placed":48}
{"pieces":["flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat","flat","flat","flat","flat","flat","flat","flat","flat","flat","flat","flat_to_left_bank","banked_left_turn_5","left_bank_to_flat","flat","flat","flat","flat","flat","flat","flat","flat","flat","flat","flat","flat","flat_to_left_bank","banked_left_turn_5","left_bank_to_flat"]}{"circuit_closed":false,"cursor":{"bank":0,"dir":0,"slope":0,"x":62,"y":58,"z":112},"placed_this_call":47,"total_placed":95}
{"pieces":["undo"]}piece[0]: unknown piece: undo
{"cursor":{"bank":2,"dir":0,"slope":0,"x":63,"y":58,"z":112},"pieces_placed":94,"removed":"left_bank_to_flat"}
{"cursor":{"bank":2,"dir":1,"slope":0,"x":66,"y":56,"z":112},"pieces_placed":93,"removed":"banked_left_turn_5"}
{"cursor":{"bank":0,"dir":1,"slope":0,"x":66,"y":55,"z":112},"pieces_placed":92,"removed":"flat_to_left_bank"}
{"pieces":["flat","flat","flat_to_left_bank","banked_left_turn_5","left_bank_to_flat"]}{"circuit_closed":true,"cursor":{"bank":0,"dir":0,"slope":0,"x":62,"y":60,"z":112},"placed_this_call":5,"total_placed":97}
{"bounds":{"max_tile_x":66,"max_tile_y":63,"max_z":344,"min_tile_x":30,"min_tile_y":39,"min_z":112},"placed_pieces":["begin_station","middle_station","middle_station","middle_station","end_station",{"chain":true,"t":"flat_to_up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25_to_flat"},"flat_to_down_25","right_turn_3_down_25","right_turn_3_down_25","right_turn_3_down_25","right_turn_3_down_25","down_25","down_25","down_25","down_25","down_25_to_flat","flat_to_up_25","half_loop_up","right_corkscrew_down","flat_to_down_25","down_25","down_25","down_25","down_25","down_25_to_flat","flat_to_up_25","right_vertical_loop","down_25_to_flat","right_corkscrew_up","left_corkscrew_down","right_corkscrew_up","left_corkscrew_down","flat_to_left_bank","banked_left_turn_5","left_bank_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat_to_up_25","up_2… (2332 chars)
{"bounds":{"max_tile_x":66,"max_tile_y":63,"max_z":344,"min_tile_x":30,"min_tile_y":39,"min_z":112},"placed_pieces":["begin_station","middle_station","middle_station","middle_station","end_station",{"chain":true,"t":"flat_to_up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25"},{"chain":true,"t":"up_25_to_flat"},"flat_to_down_25","right_turn_3_down_25","right_turn_3_down_25","right_turn_3_down_25","right_turn_3_down_25","down_25","down_25","down_25","down_25","down_25_to_flat","flat_to_up_25","half_loop_up","right_corkscrew_down","flat_to_down_25","down_25","down_25","down_25","down_25","down_25_to_flat","flat_to_up_25","right_vertical_loop","down_25_to_flat","right_corkscrew_up","left_corkscrew_down","right_corkscrew_up","left_corkscrew_down","flat_to_left_bank","banked_left_turn_5","left_bank_to_flat","flat_to_up_25","up_25","up_25_to_flat","flat_to_down_25","down_25","down_25_to_flat","flat_to_up_25","up_2… (2332 chars)
Round 1 banked at **6.84 excitement**. **Best coaster:** a 97-piece steel twister — 208-unit chain lift into a 360° descending corkscrew-spiral drop, then a half-loop→corkscrew Immelmann, a vertical loop, two more corkscrew pairs (4 inversions), and a long ground-hugging airtime-hill return with banked 5-tile turnarounds. **Excitement 6.84 / Intensity 9.76 / Nausea 5.67**, similarity 0.42 (under the 0.5 penalty threshold). Notes for round 2 (from reading `RideRatings.cpp` + `TwisterRollerCoaster.h`): max lateral G is 3.02, which trips the >2.80 penalty (+1.88 intensity) and sits right at the 10.00 cliff that costs 25% of all excitement. Banking the sloped turns and easing turn radii should drop intensity to ~7.9 and lift excitement well past 7. Other untapped free levers: ride duration ≥150 (+0.60 E, zero intensity), unbanked *sloped* turns (+0.40 E, literally zero intensity, capped at 4/6/6/7 by element count), exactly 6 inversions (+0.65 E), and 11 short tunnels (+0.31 E).