Refactor ride measurement storage

This commit is contained in:
Ted John 2019-06-09 10:55:41 +01:00 committed by Michael Steenbeek
parent 7478e13e61
commit 6f0298deb3
19 changed files with 287 additions and 253 deletions

View File

@ -5880,7 +5880,6 @@ static void window_ride_graphs_mousedown(rct_window* w, rct_widgetindex widgetIn
static void window_ride_graphs_update(rct_window* w)
{
rct_widget* widget;
rct_ride_measurement* measurement;
int32_t x;
w->frame_no++;
@ -5896,7 +5895,8 @@ static void window_ride_graphs_update(rct_window* w)
auto ride = get_ride(w->number);
if (ride != nullptr)
{
measurement = ride_get_measurement(ride, nullptr);
RideMeasurement* measurement{};
std::tie(measurement, std::ignore) = ride_get_measurement(ride);
x = measurement == nullptr ? 0 : measurement->current_item - (((widget->right - widget->left) / 4) * 3);
}
}
@ -5911,8 +5911,6 @@ static void window_ride_graphs_update(rct_window* w)
*/
static void window_ride_graphs_scrollgetheight(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height)
{
rct_ride_measurement* measurement;
window_event_invalidate_call(w);
// Set minimum size
@ -5922,7 +5920,8 @@ static void window_ride_graphs_scrollgetheight(rct_window* w, int32_t scrollInde
auto ride = get_ride(w->number);
if (ride != nullptr)
{
measurement = ride_get_measurement(ride, nullptr);
RideMeasurement* measurement{};
std::tie(measurement, std::ignore) = ride_get_measurement(ride);
if (measurement != nullptr)
{
*width = std::max<int32_t>(*width, measurement->num_items);
@ -5950,8 +5949,7 @@ static void window_ride_graphs_tooltip(rct_window* w, rct_widgetindex widgetInde
auto ride = get_ride(w->number);
if (ride != nullptr)
{
rct_string_id message;
auto measurement = ride_get_measurement(ride, &message);
auto [measurement, message] = ride_get_measurement(ride);
if (measurement != nullptr && (measurement->flags & RIDE_MEASUREMENT_FLAG_RUNNING))
{
set_format_arg(4, uint16_t, measurement->vehicle_index + 1);
@ -6053,11 +6051,11 @@ static void window_ride_graphs_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi
auto widget = &window_ride_graphs_widgets[WIDX_GRAPH];
auto stringId = STR_NONE;
rct_ride_measurement* measurement{};
RideMeasurement* measurement{};
auto ride = get_ride(w->number);
if (ride != nullptr)
{
measurement = ride_get_measurement(ride, &stringId);
std::tie(measurement, stringId) = ride_get_measurement(ride);
}
if (measurement == nullptr)
{

View File

@ -186,7 +186,7 @@ public:
ride->lift_hill_speed = RideLiftData[ride->type].minimum_speed;
ride->measurement_index = 255;
ride->measurement = {};
ride->excitement = (ride_rating)-1;
ride->cur_num_customers = 0;
ride->num_customers_timeout = 0;

View File

@ -229,10 +229,6 @@ private:
}
}
user_string_free(ride->name);
ride->type = RIDE_TYPE_NULL;
gParkValue = GetContext()->GetGameState()->GetPark().CalculateParkValue();
auto res = std::make_unique<GameActionResult>();
res->ExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION;
res->Cost = refundPrice;
@ -246,6 +242,9 @@ private:
res->Position = { x, y, z };
}
ride->Delete();
gParkValue = GetContext()->GetGameState()->GetPark().CalculateParkValue();
// Close windows related to the demolished ride
if (!(GetFlags() & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED))
{

View File

@ -212,7 +212,7 @@ public:
ride->status = _status;
ride->current_issues = 0;
ride->last_issue_time = 0;
ride_get_measurement(ride, nullptr);
ride_get_measurement(ride);
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
window_invalidate_by_number(WC_RIDE, _rideIndex);
break;

View File

@ -33,7 +33,7 @@
// This string specifies which version of network stream current build uses.
// It is used for making sure only compatible builds get connected, even within
// single OpenRCT2 version.
#define NETWORK_STREAM_VERSION "37"
#define NETWORK_STREAM_VERSION "38"
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
static Peep* _pickup_peep = nullptr;

View File

@ -428,8 +428,8 @@ struct rct1_peep : RCT12SpriteBase
uint8_t pad_C4;
union
{
uint8_t staff_id; // 0xC5
ride_id_t guest_heading_to_ride_id; // 0xC5
uint8_t staff_id; // 0xC5
uint8_t guest_heading_to_ride_id; // 0xC5
};
union
{
@ -681,7 +681,7 @@ struct rct1_s4
uint32_t unk_1CADCA;
uint16_t unk_1CADCE;
uint8_t unk_1CADD0[116];
rct_ride_measurement ride_measurements[8];
RCT12RideMeasurement ride_measurements[8];
uint32_t next_guest_index;
uint16_t game_counter_5;
uint8_t patrol_areas[(RCT1_MAX_STAFF + RCT12_STAFF_TYPE_COUNT) * RCT12_PATROL_AREA_SIZE];

View File

@ -952,7 +952,6 @@ private:
dst->sheltered_eighths = src->num_inversions >> 5;
dst->boat_hire_return_direction = src->boat_hire_return_direction;
dst->boat_hire_return_position = src->boat_hire_return_position;
dst->measurement_index = src->data_logging_index;
dst->chairlift_bullwheel_rotation = src->chairlift_bullwheel_rotation;
for (int i = 0; i < 2; i++)
{
@ -1108,23 +1107,32 @@ private:
void ImportRideMeasurements()
{
for (int32_t i = 0; i < MAX_RIDE_MEASUREMENTS; i++)
for (const auto& src : _s4.ride_measurements)
{
rct_ride_measurement* dst = get_ride_measurement(i);
rct_ride_measurement* src = &_s4.ride_measurements[i];
ImportRideMeasurement(dst, src);
if (src.ride_index != RCT12_RIDE_ID_NULL)
{
auto ride = get_ride(src.ride_index);
ride->measurement = std::make_unique<RideMeasurement>();
ride->measurement->ride = ride;
ImportRideMeasurement(*ride->measurement, src);
}
}
}
void ImportRideMeasurement(rct_ride_measurement* dst, rct_ride_measurement* src)
void ImportRideMeasurement(RideMeasurement& dst, const RCT12RideMeasurement& src)
{
*dst = *src;
for (int32_t i = 0; i < RIDE_MEASUREMENT_MAX_ITEMS; i++)
dst.flags = src.flags;
dst.last_use_tick = src.last_use_tick;
dst.num_items = src.num_items;
dst.current_item = src.current_item;
dst.vehicle_index = src.vehicle_index;
dst.current_station = src.current_station;
for (size_t i = 0; i < std::size(src.velocity); i++)
{
dst->velocity[i] /= 2;
dst->altitude[i] /= 2;
dst->vertical[i] /= 2;
dst->lateral[i] /= 2;
dst.velocity[i] = src.velocity[i] / 2;
dst.altitude[i] = src.altitude[i] / 2;
dst.vertical[i] = src.vertical[i] / 2;
dst.lateral[i] = src.lateral[i] / 2;
}
}

View File

@ -39,6 +39,9 @@
#define RCT12_PEEP_MAX_THOUGHTS 5
#define RCT12_RIDE_ID_NULL 255
#define RCT12_RIDE_MEASUREMENT_MAX_ITEMS 4800
constexpr uint16_t const RCT12_MAX_INVERSIONS = 31;
constexpr uint16_t const RCT12_MAX_GOLF_HOLES = 31;
constexpr uint16_t const RCT12_MAX_HELICES = 31;
@ -502,4 +505,20 @@ struct RCT12PeepThought
};
assert_struct_size(RCT12PeepThought, 4);
struct RCT12RideMeasurement
{
uint8_t ride_index; // 0x0000
uint8_t flags; // 0x0001
uint32_t last_use_tick; // 0x0002
uint16_t num_items; // 0x0006
uint16_t current_item; // 0x0008
uint8_t vehicle_index; // 0x000A
uint8_t current_station; // 0x000B
int8_t vertical[RCT12_RIDE_MEASUREMENT_MAX_ITEMS]; // 0x000C
int8_t lateral[RCT12_RIDE_MEASUREMENT_MAX_ITEMS]; // 0x12CC
uint8_t velocity[RCT12_RIDE_MEASUREMENT_MAX_ITEMS]; // 0x258C
uint8_t altitude[RCT12_RIDE_MEASUREMENT_MAX_ITEMS]; // 0x384C
};
assert_struct_size(RCT12RideMeasurement, 0x4B0C);
#pragma pack(pop)

View File

@ -310,7 +310,7 @@ struct RCT2SpriteVehicle : RCT12SpriteBase
int32_t remaining_distance; // 0x24
int32_t velocity; // 0x28
int32_t acceleration; // 0x2C
ride_id_t ride; // 0x30
uint8_t ride; // 0x30
uint8_t vehicle_type; // 0x31
rct_vehicle_colour colours; // 0x32
union

View File

@ -360,7 +360,7 @@ void S6Exporter::Export()
// pad_0138B582
_s6.ride_ratings_calc_data = gRideRatingsCalcData;
std::memcpy(_s6.ride_measurements, gRideMeasurements, sizeof(_s6.ride_measurements));
ExportRideMeasurements();
_s6.next_guest_index = gNextGuestNumber;
_s6.grass_and_scenery_tilepos = gGrassSceneryTileLoopPosition;
std::memcpy(_s6.patrol_areas, gStaffPatrolAreas, sizeof(_s6.patrol_areas));
@ -538,8 +538,6 @@ void S6Exporter::ExportRide(rct2_ride* dst, const Ride* src)
dst->boat_hire_return_direction = src->boat_hire_return_direction;
dst->boat_hire_return_position = src->boat_hire_return_position;
dst->measurement_index = src->measurement_index;
dst->special_track_elements = src->special_track_elements;
// pad_0D6[2];
@ -686,6 +684,60 @@ void S6Exporter::ExportRide(rct2_ride* dst, const Ride* src)
// pad_208[0x58];
}
void S6Exporter::ExportRideMeasurements()
{
// Get all the ride measurements
std::vector<const RideMeasurement*> rideMeasurements;
for (ride_id_t i = 0; i < RCT12_MAX_RIDES_IN_PARK; i++)
{
auto ride = get_ride(i);
if (ride != nullptr && ride->measurement != nullptr)
{
rideMeasurements.push_back(ride->measurement.get());
}
}
// If there are more than S6 can hold, trim it by LRU
if (rideMeasurements.size() > RCT12_RIDE_MEASUREMENT_MAX_ITEMS)
{
// Sort in order of last recently used
std::sort(rideMeasurements.begin(), rideMeasurements.end(), [](const RideMeasurement* a, const RideMeasurement* b) {
return a->last_use_tick > b->last_use_tick;
});
rideMeasurements.resize(RCT12_RIDE_MEASUREMENT_MAX_ITEMS);
}
// Convert ride measurements to S6 format
uint8_t i{};
for (auto src : rideMeasurements)
{
auto& dst = _s6.ride_measurements[i];
ExportRideMeasurement(_s6.ride_measurements[i], *src);
auto rideId = src->ride->id;
dst.ride_index = rideId;
_s6.rides[rideId].measurement_index = i;
i++;
}
}
void S6Exporter::ExportRideMeasurement(RCT12RideMeasurement& dst, const RideMeasurement& src)
{
dst.flags = src.flags;
dst.last_use_tick = src.last_use_tick;
dst.num_items = src.num_items;
dst.current_item = src.current_item;
dst.vehicle_index = src.vehicle_index;
dst.current_station = src.current_station;
for (size_t i = 0; i < std::size(src.velocity); i++)
{
dst.velocity[i] = src.velocity[i];
dst.altitude[i] = src.altitude[i];
dst.vertical[i] = src.vertical[i];
dst.lateral[i] = src.lateral[i];
}
}
void S6Exporter::ExportResearchedRideTypes()
{
std::fill(std::begin(_s6.researched_ride_types), std::end(_s6.researched_ride_types), false);

View File

@ -57,4 +57,6 @@ private:
void ExportResearchList();
void ExportMarketingCampaigns();
void ExportPeepSpawns();
void ExportRideMeasurements();
void ExportRideMeasurement(RCT12RideMeasurement& dst, const RideMeasurement& src);
};

View File

@ -396,7 +396,7 @@ public:
// pad_0138B582
gRideRatingsCalcData = _s6.ride_ratings_calc_data;
std::memcpy(gRideMeasurements, _s6.ride_measurements, sizeof(_s6.ride_measurements));
ImportRideMeasurements();
gNextGuestNumber = _s6.next_guest_index;
gGrassSceneryTileLoopPosition = _s6.grass_and_scenery_tilepos;
std::memcpy(gStaffPatrolAreas, _s6.patrol_areas, sizeof(_s6.patrol_areas));
@ -586,8 +586,6 @@ public:
dst->boat_hire_return_direction = src->boat_hire_return_direction;
dst->boat_hire_return_position = src->boat_hire_return_position;
dst->measurement_index = src->measurement_index;
dst->special_track_elements = src->special_track_elements;
// pad_0D6[2];
@ -750,6 +748,37 @@ public:
// pad_208[0x58];
}
void ImportRideMeasurements()
{
for (const auto& src : _s6.ride_measurements)
{
if (src.ride_index != RCT12_RIDE_ID_NULL)
{
auto ride = get_ride(src.ride_index);
ride->measurement = std::make_unique<RideMeasurement>();
ride->measurement->ride = ride;
ImportRideMeasurement(*ride->measurement, src);
}
}
}
void ImportRideMeasurement(RideMeasurement& dst, const RCT12RideMeasurement& src)
{
dst.flags = src.flags;
dst.last_use_tick = src.last_use_tick;
dst.num_items = src.num_items;
dst.current_item = src.current_item;
dst.vehicle_index = src.vehicle_index;
dst.current_station = src.current_station;
for (size_t i = 0; i < std::size(src.velocity); i++)
{
dst.velocity[i] = src.velocity[i];
dst.altitude[i] = src.altitude[i];
dst.vertical[i] = src.vertical[i];
dst.lateral[i] = src.lateral[i];
}
}
void ImportResearchedRideTypes()
{
set_every_ride_type_not_invented();

View File

@ -152,8 +152,6 @@ static constexpr const int32_t RideInspectionInterval[] = {
Ride gRideList[MAX_RIDES];
rct_ride_measurement gRideMeasurements[MAX_RIDE_MEASUREMENTS];
uint16_t gRideCount;
bool gGotoStartPlacementMode = false;
@ -256,11 +254,6 @@ void get_ride_entry_name(char* name, int32_t index)
name[8] = '\0';
}
rct_ride_measurement* get_ride_measurement(int32_t index)
{
return &gRideMeasurements[index];
}
rct_ride_entry* Ride::GetRideEntry() const
{
rct_ride_entry* rideEntry = get_ride_entry(subtype);
@ -955,12 +948,6 @@ void ride_init_all()
ride->id = i;
ride->type = RIDE_TYPE_NULL;
}
for (int32_t i = 0; i < MAX_RIDE_MEASUREMENTS; i++)
{
rct_ride_measurement* ride_measurement = get_ride_measurement(i);
ride_measurement->ride_index = RIDE_ID_NULL;
}
}
/**
@ -1093,7 +1080,7 @@ static void ride_remove_vehicles(Ride* ride)
*/
void ride_clear_for_construction(Ride* ride)
{
ride_measurement_clear(ride);
ride->measurement = {};
ride->lifecycle_flags &= ~(RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN);
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
@ -2071,7 +2058,7 @@ void Ride::UpdateAll()
{
if (gS6Info.editor_step <= EDITOR_STEP_INVENTIONS_LIST_SET_UP)
FOR_ALL_RIDES (i, ride)
ride->type = RIDE_TYPE_NULL;
ride->Delete();
return;
}
@ -2963,39 +2950,18 @@ static void ride_music_update(Ride* ride)
#pragma region Measurement functions
/**
*
* rct2: 0x006B642B
*/
void ride_measurement_clear(Ride* ride)
{
rct_ride_measurement* measurement;
if (ride->measurement_index == 255)
return;
measurement = get_ride_measurement(ride->measurement_index);
measurement->ride_index = RIDE_ID_NULL;
ride->measurement_index = 255;
}
/**
*
* rct2: 0x006B64F2
*/
static void ride_measurement_update(rct_ride_measurement* measurement)
static void ride_measurement_update(RideMeasurement* measurement)
{
uint16_t spriteIndex;
Ride* ride;
rct_vehicle* vehicle;
int32_t velocity, altitude, verticalG, lateralG;
ride = get_ride(measurement->ride_index);
spriteIndex = ride->vehicles[measurement->vehicle_index];
auto ride = measurement->ride;
auto spriteIndex = ride->vehicles[measurement->vehicle_index];
if (spriteIndex == SPRITE_INDEX_NULL)
return;
vehicle = GET_VEHICLE(spriteIndex);
auto vehicle = GET_VEHICLE(spriteIndex);
if (measurement->flags & RIDE_MEASUREMENT_FLAG_UNLOADING)
{
@ -3020,27 +2986,27 @@ static void ride_measurement_update(rct_ride_measurement* measurement)
if (vehicle->velocity == 0)
return;
if (measurement->current_item >= RIDE_MEASUREMENT_MAX_ITEMS)
if (measurement->current_item >= RideMeasurement::MAX_ITEMS)
return;
if (measurement->flags & RIDE_MEASUREMENT_FLAG_G_FORCES)
{
vehicle_get_g_forces(vehicle, &verticalG, &lateralG);
verticalG = std::clamp(verticalG / 8, -127, 127);
lateralG = std::clamp(lateralG / 8, -127, 127);
auto gForces = vehicle_get_g_forces(vehicle);
gForces.VerticalG = std::clamp(gForces.VerticalG / 8, -127, 127);
gForces.LateralG = std::clamp(gForces.LateralG / 8, -127, 127);
if (gScenarioTicks & 1)
{
verticalG = (verticalG + measurement->vertical[measurement->current_item]) / 2;
lateralG = (lateralG + measurement->lateral[measurement->current_item]) / 2;
gForces.VerticalG = (gForces.VerticalG + measurement->vertical[measurement->current_item]) / 2;
gForces.LateralG = (gForces.LateralG + measurement->lateral[measurement->current_item]) / 2;
}
measurement->vertical[measurement->current_item] = verticalG & 0xFF;
measurement->lateral[measurement->current_item] = lateralG & 0xFF;
measurement->vertical[measurement->current_item] = gForces.VerticalG & 0xFF;
measurement->lateral[measurement->current_item] = gForces.LateralG & 0xFF;
}
velocity = std::min(std::abs((vehicle->velocity * 5) >> 16), 255);
altitude = std::min(vehicle->z / 8, 255);
auto velocity = std::min(std::abs((vehicle->velocity * 5) >> 16), 255);
auto altitude = std::min(vehicle->z / 8, 255);
if (gScenarioTicks & 1)
{
@ -3068,136 +3034,106 @@ void ride_measurements_update()
return;
// For each ride measurement
for (int32_t i = 0; i < MAX_RIDE_MEASUREMENTS; i++)
ride_id_t i{};
Ride* ride{};
FOR_ALL_RIDES (i, ride)
{
rct_ride_measurement* measurement = get_ride_measurement(i);
if (measurement->ride_index == RIDE_ID_NULL)
continue;
Ride* ride = get_ride(measurement->ride_index);
if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) || ride->status == RIDE_STATUS_SIMULATING)
continue;
if (measurement->flags & RIDE_MEASUREMENT_FLAG_RUNNING)
auto measurement = ride->measurement.get();
if (measurement != nullptr && (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) && ride->status != RIDE_STATUS_SIMULATING)
{
ride_measurement_update(measurement);
}
else
{
// For each vehicle
for (int32_t j = 0; j < ride->num_vehicles; j++)
if (measurement->flags & RIDE_MEASUREMENT_FLAG_RUNNING)
{
uint16_t vehicleSpriteIdx = ride->vehicles[j];
if (vehicleSpriteIdx == SPRITE_INDEX_NULL)
continue;
rct_vehicle* vehicle = GET_VEHICLE(vehicleSpriteIdx);
if (vehicle->status == VEHICLE_STATUS_DEPARTING || vehicle->status == VEHICLE_STATUS_TRAVELLING_CABLE_LIFT)
ride_measurement_update(measurement);
}
else
{
// For each vehicle
for (int32_t j = 0; j < ride->num_vehicles; j++)
{
measurement->vehicle_index = j;
measurement->current_station = vehicle->current_station;
measurement->flags |= RIDE_MEASUREMENT_FLAG_RUNNING;
measurement->flags &= ~RIDE_MEASUREMENT_FLAG_UNLOADING;
ride_measurement_update(measurement);
break;
uint16_t vehicleSpriteIdx = ride->vehicles[j];
if (vehicleSpriteIdx != SPRITE_INDEX_NULL)
{
auto vehicle = GET_VEHICLE(vehicleSpriteIdx);
if (vehicle->status == VEHICLE_STATUS_DEPARTING
|| vehicle->status == VEHICLE_STATUS_TRAVELLING_CABLE_LIFT)
{
measurement->vehicle_index = j;
measurement->current_station = vehicle->current_station;
measurement->flags |= RIDE_MEASUREMENT_FLAG_RUNNING;
measurement->flags &= ~RIDE_MEASUREMENT_FLAG_UNLOADING;
ride_measurement_update(measurement);
break;
}
}
}
}
}
}
}
static rct_ride_measurement* ride_get_existing_measurement(ride_id_t rideIndex)
{
for (int32_t i = 0; i < MAX_RIDE_MEASUREMENTS; i++)
{
rct_ride_measurement* measurement = get_ride_measurement(i);
if (measurement->ride_index == rideIndex)
return measurement;
}
return nullptr;
}
static int32_t ride_get_free_measurement()
{
for (int32_t i = 0; i < MAX_RIDE_MEASUREMENTS; i++)
{
rct_ride_measurement* measurement = get_ride_measurement(i);
if (measurement->ride_index == RIDE_ID_NULL)
return i;
}
return -1;
}
/**
*
* rct2: 0x006B66D9
* If there are more than the threshold of allowed ride measurements, free the non-LRU one.
*/
rct_ride_measurement* ride_get_measurement(Ride* ride, rct_string_id* message)
static void ride_free_old_measurements()
{
size_t numRideMeasurements;
do
{
ride_id_t i{};
Ride* ride{};
Ride* lruRide{};
numRideMeasurements = 0;
FOR_ALL_RIDES (i, ride)
{
if (ride->measurement != nullptr)
{
if (lruRide == nullptr || ride->measurement->last_use_tick > lruRide->measurement->last_use_tick)
{
lruRide = ride;
}
numRideMeasurements++;
}
}
if (numRideMeasurements > MAX_RIDE_MEASUREMENTS && lruRide != nullptr)
{
lruRide->measurement = {};
numRideMeasurements--;
}
} while (numRideMeasurements > MAX_RIDE_MEASUREMENTS);
}
std::pair<RideMeasurement*, rct_string_id> ride_get_measurement(Ride* ride)
{
// Check if ride type supports data logging
if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_DATA_LOGGING))
{
if (message != nullptr)
*message = STR_DATA_LOGGING_NOT_AVAILABLE_FOR_THIS_TYPE_OF_RIDE;
return nullptr;
return { nullptr, STR_DATA_LOGGING_NOT_AVAILABLE_FOR_THIS_TYPE_OF_RIDE };
}
// Check if a measurement already exists for this ride
rct_ride_measurement* measurement = ride_get_existing_measurement(ride->id);
auto& measurement = ride->measurement;
if (measurement == nullptr)
{
// Find a free measurement
int32_t i = ride_get_free_measurement();
if (i == -1)
{
// Use last recently used measurement for some other ride
int32_t lruIndex = 0;
uint32_t lruTicks = 0xFFFFFFFF;
for (i = 0; i < MAX_RIDE_MEASUREMENTS; i++)
{
measurement = get_ride_measurement(i);
if (measurement->last_use_tick <= lruTicks)
{
lruTicks = measurement->last_use_tick;
lruIndex = i;
}
}
i = lruIndex;
measurement = get_ride_measurement(i);
get_ride(measurement->ride_index)->measurement_index = 255;
}
else
{
measurement = get_ride_measurement(i);
}
measurement->ride_index = ride->id;
ride->measurement_index = i;
measurement->flags = 0;
measurement = std::make_unique<RideMeasurement>();
measurement->ride = ride;
if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_G_FORCES))
{
measurement->flags |= RIDE_MEASUREMENT_FLAG_G_FORCES;
measurement->num_items = 0;
measurement->current_item = 0;
}
ride_free_old_measurements();
assert(ride->measurement != nullptr);
}
measurement->last_use_tick = gScenarioTicks;
if (measurement->flags & 1)
{
if (message != nullptr)
*message = STR_EMPTY;
return measurement;
return { measurement.get(), STR_EMPTY };
}
else
{
set_format_arg(0, rct_string_id, RideComponentNames[RideNameConvention[ride->type].vehicle].singular);
set_format_arg(2, rct_string_id, RideComponentNames[RideNameConvention[ride->type].station].singular);
if (message != nullptr)
*message = STR_DATA_LOGGING_WILL_START_WHEN_NEXT_LEAVES;
return nullptr;
return { measurement.get(), STR_DATA_LOGGING_WILL_START_WHEN_NEXT_LEAVES };
}
}
@ -6652,7 +6588,7 @@ bool ride_are_all_possible_entrances_and_exits_built(Ride* ride)
*/
void invalidate_test_results(Ride* ride)
{
ride_measurement_clear(ride);
ride->measurement = {};
ride->excitement = RIDE_RATING_UNDEFINED;
ride->lifecycle_flags &= ~RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags &= ~RIDE_LIFECYCLE_TEST_IN_PROGRESS;
@ -7440,6 +7376,7 @@ rct_vehicle* ride_get_broken_vehicle(Ride* ride)
void Ride::Delete()
{
user_string_free(name);
measurement = {};
type = RIDE_TYPE_NULL;
}

View File

@ -21,6 +21,7 @@
interface IObjectManager;
class StationObject;
struct Peep;
struct Ride;
struct Staff;
#define MAX_RIDE_TYPES_PER_RIDE_ENTRY 3
@ -35,7 +36,6 @@ struct Staff;
#define CUSTOMER_HISTORY_SIZE 10
#define MAX_CARS_PER_TRAIN 255
#define MAX_STATIONS 4
#define RIDE_MEASUREMENT_MAX_ITEMS 4800
#define MAX_RIDES 255
#define RIDE_ID_NULL 255
#define RIDE_ADJACENCY_CHECK_DISTANCE 5
@ -160,6 +160,23 @@ struct RideStation
static constexpr uint8_t NO_TRAIN = std::numeric_limits<uint8_t>::max();
};
struct RideMeasurement
{
static constexpr size_t MAX_ITEMS = 4800;
Ride* ride{};
uint8_t flags{};
uint32_t last_use_tick{};
uint16_t num_items{};
uint16_t current_item{};
uint8_t vehicle_index{};
uint8_t current_station{};
int8_t vertical[MAX_ITEMS]{};
int8_t lateral[MAX_ITEMS]{};
uint8_t velocity[MAX_ITEMS]{};
uint8_t altitude[MAX_ITEMS]{};
};
/**
* Ride structure.
*
@ -212,7 +229,6 @@ struct Ride
uint8_t boat_hire_return_direction;
LocationXY8 boat_hire_return_position;
uint8_t measurement_index;
// bits 0 through 4 are the number of helix sections
// bit 5: spinning tunnel, water splash, or rapids
// bit 6: log reverser, waterfall
@ -352,6 +368,8 @@ struct Ride
uint16_t holes;
uint8_t sheltered_eighths;
std::unique_ptr<RideMeasurement> measurement;
private:
void Update();
void UpdateChairlift();
@ -403,26 +421,6 @@ public:
#pragma pack(push, 1)
/**
* Ride measurement structure.
* size: 0x04B0C
*/
struct rct_ride_measurement
{
ride_id_t ride_index; // 0x0000
uint8_t flags; // 0x0001
uint32_t last_use_tick; // 0x0002
uint16_t num_items; // 0x0006
uint16_t current_item; // 0x0008
uint8_t vehicle_index; // 0x000A
uint8_t current_station; // 0x000B
int8_t vertical[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x000C
int8_t lateral[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x12CC
uint8_t velocity[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x258C
uint8_t altitude[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x384C
};
assert_struct_size(rct_ride_measurement, 0x4b0c);
struct track_begin_end
{
int32_t begin_x;
@ -982,7 +980,7 @@ extern const rct_ride_properties RideProperties[RIDE_TYPE_COUNT];
Ride* get_ride(int32_t index);
rct_ride_entry* get_ride_entry(int32_t index);
void get_ride_entry_name(char* name, int32_t index);
rct_ride_measurement* get_ride_measurement(int32_t index);
RideMeasurement* get_ride_measurement(int32_t index);
/**
* Helper macro loop for enumerating through all the non null rides.
@ -998,7 +996,6 @@ extern const uint8_t gRideClassifications[MAX_RIDES];
extern Ride gRideList[MAX_RIDES];
extern const rct_string_id ColourSchemeNames[4];
extern rct_ride_measurement gRideMeasurements[MAX_RIDE_MEASUREMENTS];
extern uint16_t gRideCount;
extern money32 _currentTrackPrice;
@ -1070,9 +1067,8 @@ int32_t ride_get_unused_preset_vehicle_colour(uint8_t ride_sub_type);
void ride_set_vehicle_colours_to_random_preset(Ride* ride, uint8_t preset_index);
uint8_t* get_ride_entry_indices_for_ride_type(uint8_t rideType);
void reset_type_to_ride_entry_index_map(IObjectManager& objectManager);
void ride_measurement_clear(Ride* ride);
void ride_measurements_update();
rct_ride_measurement* ride_get_measurement(Ride* ride, rct_string_id* message);
std::pair<RideMeasurement*, rct_string_id> ride_get_measurement(Ride* ride);
void ride_breakdown_add_news_item(Ride* ride);
Peep* ride_find_closest_mechanic(Ride* ride, int32_t forInspection);
int32_t ride_is_valid_for_open(Ride* ride, int32_t goingToBeOpen, bool isApplying);

View File

@ -1798,6 +1798,7 @@ static bool track_design_place_preview(rct_track_td6* td6, money32* cost, Ride**
_currentTrackPieceDirection = backup_rotation;
user_string_free(ride->name);
ride->type = RIDE_TYPE_NULL;
ride->measurement = {};
byte_9D8150 = false;
return false;
}

View File

@ -1557,32 +1557,27 @@ static void vehicle_update_measurements(rct_vehicle* vehicle)
if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_G_FORCES))
{
int32_t vertical_g, lateral_g;
vehicle_get_g_forces(vehicle, &vertical_g, &lateral_g);
auto gForces = vehicle_get_g_forces(vehicle);
gForces.VerticalG += ride->previous_vertical_g;
gForces.LateralG += ride->previous_lateral_g;
gForces.VerticalG /= 2;
gForces.LateralG /= 2;
vertical_g += ride->previous_vertical_g;
lateral_g += ride->previous_lateral_g;
vertical_g >>= 1;
lateral_g >>= 1;
ride->previous_vertical_g = vertical_g;
ride->previous_lateral_g = lateral_g;
if (vertical_g <= 0)
ride->previous_vertical_g = gForces.VerticalG;
ride->previous_lateral_g = gForces.LateralG;
if (gForces.VerticalG <= 0)
{
ride->total_air_time++;
}
if (vertical_g > ride->max_positive_vertical_g)
ride->max_positive_vertical_g = vertical_g;
if (gForces.VerticalG > ride->max_positive_vertical_g)
ride->max_positive_vertical_g = gForces.VerticalG;
if (vertical_g < ride->max_negative_vertical_g)
ride->max_negative_vertical_g = vertical_g;
if (gForces.VerticalG < ride->max_negative_vertical_g)
ride->max_negative_vertical_g = gForces.VerticalG;
lateral_g = abs(lateral_g);
if (lateral_g > ride->max_lateral_g)
ride->max_lateral_g = lateral_g;
gForces.LateralG = std::abs(gForces.LateralG);
ride->max_lateral_g = std::max(ride->max_lateral_g, (fixed16_2dp)gForces.LateralG);
}
}
@ -5706,7 +5701,7 @@ produceScream:
* dx: lateralG
* esi: vehicle
*/
void vehicle_get_g_forces(const rct_vehicle* vehicle, int32_t* verticalG, int32_t* lateralG)
GForces vehicle_get_g_forces(const rct_vehicle* vehicle)
{
int32_t gForceVert = (((int64_t)0x280000) * Unk9A37E4[vehicle->vehicle_sprite_type]) >> 32;
gForceVert = (((int64_t)gForceVert) * Unk9A39C4[vehicle->bank_rotation]) >> 32;
@ -6221,11 +6216,7 @@ void vehicle_get_g_forces(const rct_vehicle* vehicle, int32_t* verticalG, int32_
gForceLateral *= 10;
gForceVert >>= 16;
gForceLateral >>= 16;
if (verticalG != nullptr)
*verticalG = (int16_t)(gForceVert & 0xFFFF);
if (lateralG != nullptr)
*lateralG = (int16_t)(gForceLateral & 0xFFFF);
return { (int16_t)(gForceVert & 0xFFFF), (int16_t)(gForceLateral & 0xFFFF) };
}
void vehicle_set_map_toolbar(const rct_vehicle* vehicle)
@ -6531,9 +6522,7 @@ bool vehicle_update_dodgems_collision(rct_vehicle* vehicle, int16_t x, int16_t y
*/
static void vehicle_update_track_motion_up_stop_check(rct_vehicle* vehicle)
{
rct_ride_entry_vehicle* vehicleEntry = vehicle_get_vehicle_entry(vehicle);
int32_t verticalG, lateralG;
auto vehicleEntry = vehicle_get_vehicle_entry(vehicle);
if (vehicleEntry == nullptr)
{
return;
@ -6545,18 +6534,18 @@ static void vehicle_update_track_motion_up_stop_check(rct_vehicle* vehicle)
int32_t trackType = vehicle->track_type >> 2;
if (!track_element_is_covered(trackType))
{
vehicle_get_g_forces(vehicle, &verticalG, &lateralG);
lateralG = abs(lateralG);
if (lateralG <= 150)
auto gForces = vehicle_get_g_forces(vehicle);
gForces.LateralG = std::abs(gForces.LateralG);
if (gForces.LateralG <= 150)
{
if (dword_9A2970[vehicle->vehicle_sprite_type] < 0)
{
if (verticalG > -40)
if (gForces.VerticalG > -40)
{
return;
}
}
else if (verticalG > -80)
else if (gForces.VerticalG > -80)
{
return;
}
@ -6574,18 +6563,18 @@ static void vehicle_update_track_motion_up_stop_check(rct_vehicle* vehicle)
int32_t trackType = vehicle->track_type >> 2;
if (!track_element_is_covered(trackType))
{
vehicle_get_g_forces(vehicle, &verticalG, &lateralG);
auto gForces = vehicle_get_g_forces(vehicle);
if (dword_9A2970[vehicle->vehicle_sprite_type] < 0)
{
if (verticalG > -45)
if (gForces.VerticalG > -45)
{
return;
}
}
else
{
if (verticalG > -80)
if (gForces.VerticalG > -80)
{
return;
}

View File

@ -457,10 +457,16 @@ enum
#define VEHICLE_SEAT_PAIR_FLAG 0x80
#define VEHICLE_SEAT_NUM_MASK 0x7F
struct GForces
{
int32_t VerticalG{};
int32_t LateralG{};
};
rct_vehicle* try_get_vehicle(uint16_t spriteIndex);
void vehicle_update_all();
void vehicle_sounds_update();
void vehicle_get_g_forces(const rct_vehicle* vehicle, int32_t* verticalG, int32_t* lateralG);
GForces vehicle_get_g_forces(const rct_vehicle* vehicle);
void vehicle_set_map_toolbar(const rct_vehicle* vehicle);
int32_t vehicle_is_used_in_pairs(const rct_vehicle* vehicle);
int32_t vehicle_update_track_motion(rct_vehicle* vehicle, int32_t* outStation);

View File

@ -265,7 +265,7 @@ struct rct_s6_data
uint8_t pad_0138B582[2];
rct_ride_rating_calc_data ride_ratings_calc_data;
uint8_t pad_0138B5D0[60];
rct_ride_measurement ride_measurements[8];
RCT12RideMeasurement ride_measurements[8];
uint32_t next_guest_index;
uint16_t grass_and_scenery_tilepos;
uint32_t patrol_areas[(RCT2_MAX_STAFF + RCT12_STAFF_TYPE_COUNT) * RCT12_PATROL_AREA_SIZE];

View File

@ -46,13 +46,11 @@ namespace TestPaint
gPaintSession.DPI = dpi;
{
Ride ride = {};
ride.entrance_style = 0;
static rct_ride_entry rideEntry = {};
rct_ride_entry_vehicle vehicleEntry{};
vehicleEntry.base_image_id = 0x70000;
rideEntry.vehicles[0] = vehicleEntry;
gRideList[0] = ride;
gRideList[0] = {};
gRideEntries[0] = &rideEntry;
}
{