diff --git a/src/game.h b/src/game.h index b5df70cc6b..cdc1fb865a 100644 --- a/src/game.h +++ b/src/game.h @@ -33,7 +33,7 @@ enum GAME_COMMAND { GAME_COMMAND_6, GAME_COMMAND_DEMOLISH_RIDE, GAME_COMMAND_SET_RIDE_STATUS, // 8 - GAME_COMMAND_9, + GAME_COMMAND_SET_RIDE_VEHICLES, GAME_COMMAND_SET_RIDE_NAME, GAME_COMMAND_SET_RIDE_SETTING, GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, diff --git a/src/ride/ride.c b/src/ride/ride.c index c57e040cba..9961362712 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -3363,7 +3363,7 @@ void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int * } ride->mode = new_value; - RCT2_CALLPROC_X(0x6DD57D, 0, 0, 0, ride_id, 0, 0, 0); + ride_update_max_vehicles(ride_id); break; case 1: ride->depart_flags = new_value; @@ -5066,19 +5066,169 @@ void ride_entry_get_train_layout(int rideEntryIndex, int numCarsPerTrain, uint8 for (int i = 0; i < numCarsPerTrain; i++) { uint8 vehicleType = rideEntry->default_vehicle; - if (i == 0) { - if (rideEntry->front_vehicle != 255) - vehicleType = rideEntry->front_vehicle; - } else if (i == 1) { - if (rideEntry->second_vehicle != 255) - vehicleType = rideEntry->second_vehicle; - } else if (i == 2) { - if (rideEntry->third_vehicle != 255) - vehicleType = rideEntry->third_vehicle; - } else if (i == numCarsPerTrain - 1) { - if (rideEntry->rear_vehicle != 255) - vehicleType = rideEntry->rear_vehicle; + if (i == 0 && rideEntry->front_vehicle != 255) { + vehicleType = rideEntry->front_vehicle; + } else if (i == 1 && rideEntry->second_vehicle != 255) { + vehicleType = rideEntry->second_vehicle; + } else if (i == 2 && rideEntry->third_vehicle != 255) { + vehicleType = rideEntry->third_vehicle; + } else if (i == numCarsPerTrain - 1 && rideEntry->rear_vehicle != 255) { + vehicleType = rideEntry->rear_vehicle; } trainLayout[i] = vehicleType; } } + +int ride_get_smallest_station_length(rct_ride *ride) +{ + uint32 result = -1; + for (int i = 0; i < 4; i++) { + if (ride->station_starts[i] != 0xFFFF) { + result = min(result, (uint32)(ride->station_length[i] & 0x0F)); + } + } + return (int)result; +} + +static int sub_6CB3AA(rct_ride *ride) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + + edi = (int)ride; + RCT2_CALLFUNC_X(0x006CB3AA, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return eax; +} + +/** + * + * rct2: 0x006DD57D + */ +void ride_update_max_vehicles(int rideIndex) +{ + rct_ride *ride; + rct_ride_type *rideEntry; + rct_ride_type_vehicle *vehicleEntry; + uint8 trainLayout[16], numCarsPerTrain, numVehicles; + int trainLength, maxNumTrains; + + ride = GET_RIDE(rideIndex); + if (ride->subtype == 0xFF) + return; + + rideEntry = GET_RIDE_ENTRY(ride->subtype); + if (rideEntry->cars_per_flat_ride == 0xFF) { + ride->num_cars_per_train = max(rideEntry->min_cars_in_train, ride->num_cars_per_train); + ride->min_max_cars_per_train = rideEntry->max_cars_in_train | (rideEntry->min_cars_in_train << 4); + + // Calculate maximum train length based on smallest station length + int stationLength = ride_get_smallest_station_length(ride); + if (stationLength == -1) + return; + + stationLength = (stationLength * 0x44180) - 0x16B2A; + int maxFriction = RCT2_GLOBAL(0x0097D21B + (ride->type * 8), uint8) << 8; + int maxCarsPerTrain = 1; + for (int numCars = rideEntry->max_cars_in_train; numCars > 0; numCars--) { + ride_entry_get_train_layout(ride->subtype, numCars, trainLayout); + trainLength = 0; + int totalFriction = 0; + for (int i = 0; i < numCars; i++) { + vehicleEntry = &rideEntry->vehicles[trainLayout[i]]; + trainLength += vehicleEntry->var_04; + totalFriction += vehicleEntry->var_08; + } + + if (trainLength <= stationLength && totalFriction <= maxFriction) { + maxCarsPerTrain = numCars; + break; + } + } + maxCarsPerTrain = max(maxCarsPerTrain, rideEntry->min_cars_in_train); + ride->min_max_cars_per_train = maxCarsPerTrain | (rideEntry->min_cars_in_train << 4); + + switch (ride->mode) { + case RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED: + case RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED: + maxNumTrains = clamp(1, ride->num_stations + ride->num_block_brakes - 1, 31); + break; + case RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE: + case RIDE_MODE_POWERED_LAUNCH_PASSTROUGH: + case RIDE_MODE_SHUTTLE: + case RIDE_MODE_LIM_POWERED_LAUNCH: + case RIDE_MODE_POWERED_LAUNCH: + maxNumTrains = 1; + break; + default: + // Calculate maximum number of trains + ride_entry_get_train_layout(ride->subtype, maxCarsPerTrain, trainLayout); + trainLength = 0; + for (int i = 0; i < maxCarsPerTrain; i++) { + vehicleEntry = &rideEntry->vehicles[trainLayout[i]]; + trainLength += vehicleEntry->var_04; + } + + int totalLength = trainLength / 2; + if (maxCarsPerTrain != 1) + totalLength /= 2; + + maxNumTrains = 0; + do { + maxNumTrains++; + totalLength += trainLength; + } while (totalLength <= stationLength); + + if ( + (ride->mode != RIDE_MODE_STATION_TO_STATION && ride->mode != RIDE_MODE_CONTINUOUS_CIRCUIT) || + !(RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 0x40) + ) { + maxNumTrains = min(maxNumTrains, 31); + } else { + ride_entry_get_train_layout(ride->subtype, maxCarsPerTrain, trainLayout); + vehicleEntry = &rideEntry->vehicles[trainLayout[0]]; + int unk = vehicleEntry->var_5C; + + int totalSpacing = 0; + for (int i = 0; i < maxCarsPerTrain; i++) { + vehicleEntry = &rideEntry->vehicles[trainLayout[i]]; + totalSpacing += vehicleEntry->var_04; + } + + totalSpacing >>= 13; + int unk2 = sub_6CB3AA(ride) / 4; + if (unk > 10) { + unk2 = (unk2 * 3) / 4; + } + if (unk > 25) { + unk2 = (unk2 * 3) / 4; + } + if (unk > 40) { + unk2 = (unk2 * 3) / 4; + } + + maxNumTrains = 0; + int unk3 = 0; + do { + maxNumTrains++; + unk3 += totalSpacing; + } while (maxNumTrains < 31 && unk3 < unk2); + } + break; + } + ride->max_trains = maxNumTrains; + + numCarsPerTrain = min(ride->var_0CB, maxCarsPerTrain); + numVehicles = min(ride->var_0CA, maxNumTrains); + } else { + ride->max_trains = rideEntry->cars_per_flat_ride; + ride->min_max_cars_per_train = rideEntry->max_cars_in_train | (rideEntry->min_cars_in_train << 4); + numCarsPerTrain = rideEntry->max_cars_in_train; + numVehicles = min(ride->var_0CA, rideEntry->cars_per_flat_ride); + } + + // Refresh new current num vehicles / num cars per vehicle + if (numVehicles != ride->num_vehicles || numCarsPerTrain != ride->num_cars_per_train) { + ride->num_cars_per_train = numCarsPerTrain; + ride->num_vehicles = numVehicles; + window_invalidate_by_number(WC_RIDE, rideIndex); + } +} \ No newline at end of file diff --git a/src/ride/ride.h b/src/ride/ride.h index 26c69916c1..05bce45c8d 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -154,7 +154,7 @@ typedef struct { uint16 overall_view; // 0x050 00XX = X, XX00 = Y (* 32 + 16) uint16 station_starts[4]; // 0x052 uint8 station_heights[4]; // 0x05A - uint8 pad_05E[0x4]; + uint8 station_length[4]; // 0x05E uint8 station_depart[4]; // 0x062 uint8 var_066[4]; uint16 entrances[4]; // 0x06A @@ -168,9 +168,10 @@ typedef struct { uint8 num_stations; // 0x0C7 uint8 num_vehicles; // 0x0C8 uint8 num_cars_per_train; // 0x0C9 - uint8 pad_0CA[0x2]; - uint8 var_0CC; - uint8 var_0CD; + uint8 var_0CA; + uint8 var_0CB; + uint8 max_trains; // 0x0CC + uint8 min_max_cars_per_train; // 0x0CD uint8 min_waiting_time; // 0x0CE uint8 max_waiting_time; // 0x0CF union { @@ -938,5 +939,6 @@ bool ride_are_all_possible_entrances_and_exits_built(rct_ride *ride); void ride_fix_breakdown(int rideIndex, int reliabilityIncreaseFactor); void ride_entry_get_train_layout(int rideEntryIndex, int numCarsPerTrain, uint8 *trainLayout); +void ride_update_max_vehicles(int rideIndex); #endif diff --git a/src/ride/track.c b/src/ride/track.c index 06ca30f6ee..46e91b162a 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -3250,14 +3250,14 @@ void game_command_place_track_design(int* eax, int* ebx, int* ecx, int* edx, int } if (entry_index != 0xFF){ - game_do_command(0, GAME_COMMAND_FLAG_APPLY | (2 << 8), 0, rideIndex | (entry_index << 8), GAME_COMMAND_9, 0, 0); + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (2 << 8), 0, rideIndex | (entry_index << 8), GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0); } game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->ride_mode << 8), 0, rideIndex | (0 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); - game_do_command(0, GAME_COMMAND_FLAG_APPLY | (0 << 8), 0, rideIndex | (track_design->number_of_trains << 8), GAME_COMMAND_9, 0, 0); + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (0 << 8), 0, rideIndex | (track_design->number_of_trains << 8), GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0); - game_do_command(0, GAME_COMMAND_FLAG_APPLY | (1 << 8), 0, rideIndex | (track_design->number_of_cars_per_train << 8), GAME_COMMAND_9, 0, 0); + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (1 << 8), 0, rideIndex | (track_design->number_of_cars_per_train << 8), GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0); game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->depart_flags << 8), 0, rideIndex | (1 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); diff --git a/src/windows/ride.c b/src/windows/ride.c index 7c7d6b9f28..c7e2f8b137 100644 --- a/src/windows/ride.c +++ b/src/windows/ride.c @@ -1419,9 +1419,8 @@ static void window_ride_set_page(rct_window *w, int page) w->frame_no = 0; w->var_492 = 0; - if (page == WINDOW_RIDE_PAGE_VEHICLE){ - // Reload the vehicle settings - RCT2_CALLPROC_X(0x006DD57D, 0, 0, 0, w->number, 0, 0, 0); + if (page == WINDOW_RIDE_PAGE_VEHICLE) { + ride_update_max_vehicles(w->number); } if (w->viewport != NULL) { @@ -2401,7 +2400,7 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], DROPDOWN_FLAG_STAY_OPEN, - ride->var_0CC, + ride->max_trains, widget->right - dropdownWidget->left ); @@ -2414,8 +2413,8 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi gDropdownItemsChecked = (1 << (ride->num_vehicles - 1)); break; case WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN: - minCars = (ride->var_0CD >> 4); - maxCars = (ride->var_0CD & 0x0F); + minCars = (ride->min_max_cars_per_train >> 4); + maxCars = (ride->min_max_cars_per_train & 0x0F); window_dropdown_show_text_custom_width( w->x + dropdownWidget->left, @@ -2466,15 +2465,15 @@ static void window_ride_vehicle_dropdown() dropdownIndex = (gDropdownItemsArgs[dropdownIndex] >> 16) & 0xFFFF; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1018; - game_do_command(0, (2 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_9, 0, 0); + game_do_command(0, (2 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0); break; case WIDX_VEHICLE_TRAINS_DROPDOWN: RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1020; - game_do_command(0, (0 << 8) | 1, 0, ((dropdownIndex + 1) << 8) | w->number, GAME_COMMAND_9, 0, 0); + game_do_command(0, (0 << 8) | 1, 0, ((dropdownIndex + 1) << 8) | w->number, GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0); break; case WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN: RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1019; - game_do_command(0, (1 << 8) | 1, 0, ((rideEntry->min_cars_in_train + dropdownIndex) << 8) | w->number, GAME_COMMAND_9, 0, 0); + game_do_command(0, (1 << 8) | 1, 0, ((rideEntry->min_cars_in_train + dropdownIndex) << 8) | w->number, GAME_COMMAND_SET_RIDE_VEHICLES, 0, 0); break; } }