1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-20 21:43:06 +01:00

Fix #2614: Junior Roller Coaster - Invisible First Vehicle

This commit is contained in:
Michael Steenbeek
2024-09-07 21:23:58 +02:00
committed by GitHub
parent 336f9eab20
commit 4fd07d3216
4 changed files with 134 additions and 16 deletions

View File

@@ -1,6 +1,7 @@
0.4.15 (in development)
------------------------------------------------------------------------
- Feature: [#15642] Track design placement can now use contruction modifier keys (ctrl/shift).
- Fix: [#2614] The colour tab of the ride window does not hide invisible cars (original bug).
- Fix: [#21959] “Save this before...?” message does not appear when selecting “New Game”.
- Fix: [#22231] Invalid object version can cause a crash.
- Fix: [#22653] Add several .parkpatch files for missing water tiles in RCT1 and RCT2 scenarios.

View File

@@ -657,6 +657,90 @@ namespace OpenRCT2::Ui::Windows
std::vector<EntranceTypeLabel> _entranceDropdownData;
bool _autoScrollGraph = true;
uint8_t getNumVisibleCars()
{
auto* ride = GetRide(rideId);
if (ride == nullptr)
return 0;
auto* rideEntry = ride->GetRideEntry();
if (rideEntry == nullptr)
return 0;
uint8_t numItems = 0;
for (auto i = 0; i < ride->num_cars_per_train; i++)
{
const auto& carEntry = rideEntry
->Cars[RideEntryGetVehicleAtPosition(ride->subtype, ride->num_cars_per_train, i)];
if (carEntry.isVisible())
numItems++;
}
return numItems;
}
uint8_t dropdownIndexToCarIndex(int32_t dropdownIndex) const
{
auto* ride = GetRide(rideId);
if (ride == nullptr || ride->vehicleColourSettings != VehicleColourSettings::perCar)
return dropdownIndex;
auto* rideEntry = ride->GetRideEntry();
if (rideEntry == nullptr)
return dropdownIndex;
// `dropdownIndex` will contain a number picked from the visible cars.
// Convert this to the actual index.
auto carDropdownIndex = -1;
for (auto carIndex = 0; carIndex < ride->num_cars_per_train; carIndex++)
{
const auto& carEntry = rideEntry->Cars[RideEntryGetVehicleAtPosition(
ride->subtype, ride->num_cars_per_train, carIndex)];
if (!carEntry.isVisible())
continue;
carDropdownIndex++;
if (dropdownIndex == carDropdownIndex)
{
return carIndex;
}
}
// Should never happen
return dropdownIndex;
}
int32_t carIndexToDropdownIndex(uint8_t selectedCarIndex) const
{
auto* ride = GetRide(rideId);
if (ride == nullptr || ride->vehicleColourSettings != VehicleColourSettings::perCar)
return selectedCarIndex;
auto* rideEntry = ride->GetRideEntry();
if (rideEntry == nullptr)
return selectedCarIndex;
// `selectedCarIndex` will contain an offset that includes invisible cars.
// Convert this to the corresponding dropdown index of actually visible cars.
auto carDropdownIndex = -1;
for (auto carIndex = 0; carIndex < ride->num_cars_per_train; carIndex++)
{
const auto& carEntry = rideEntry->Cars[RideEntryGetVehicleAtPosition(
ride->subtype, ride->num_cars_per_train, carIndex)];
if (!carEntry.isVisible())
continue;
carDropdownIndex++;
if (carIndex == selectedCarIndex)
{
return carDropdownIndex;
}
}
// Should never happen
return selectedCarIndex;
}
public:
RideWindow(const Ride& ride)
{
@@ -1110,7 +1194,7 @@ namespace OpenRCT2::Ui::Windows
void ResetVehicleIndex()
{
_vehicleIndex = 0;
_vehicleIndex = dropdownIndexToCarIndex(0);
}
private:
@@ -4305,18 +4389,25 @@ namespace OpenRCT2::Ui::Windows
break;
case WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN:
{
for (auto i = 0; i < 3; i++)
// Train, boat, ...
auto vehicleTypeName = GetRideComponentName(ride->GetRideTypeDescriptor().NameConvention.vehicle).singular;
auto numDropdownItems = 2;
gDropdownItems[0].Format = STR_DROPDOWN_MENU_LABEL;
gDropdownItems[0].Args = STR_ALL_VEHICLES_IN_SAME_COLOURS;
gDropdownItems[1].Format = STR_DROPDOWN_MENU_LABEL;
gDropdownItems[1].Args = (vehicleTypeName << 16) | STR_DIFFERENT_COLOURS_PER;
if (getNumVisibleCars() > 1)
{
gDropdownItems[i].Format = STR_DROPDOWN_MENU_LABEL;
gDropdownItems[i].Args = (GetRideComponentName(ride->GetRideTypeDescriptor().NameConvention.vehicle)
.singular
<< 16)
| VehicleColourSchemeNames[i];
numDropdownItems++;
gDropdownItems[2].Format = STR_DROPDOWN_MENU_LABEL;
gDropdownItems[2].Args = STR_DIFFERENT_COLOURS_PER_VEHICLE;
}
WindowDropdownShowTextCustomWidth(
{ windowPos.x + dropdownWidget->left, windowPos.y + dropdownWidget->top }, dropdownWidget->height() + 1,
colours[1], 0, Dropdown::Flag::StayOpen, rideEntry->max_cars_in_train > 1 ? 3 : 2,
colours[1], 0, Dropdown::Flag::StayOpen, numDropdownItems,
widgets[widgetIndex].right - dropdownWidget->left);
Dropdown::SetChecked(EnumValue(ride->vehicleColourSettings), true);
@@ -4330,19 +4421,33 @@ namespace OpenRCT2::Ui::Windows
stringId = ride->vehicleColourSettings == VehicleColourSettings::perTrain ? STR_RIDE_COLOUR_TRAIN_OPTION
: STR_RIDE_COLOUR_VEHICLE_OPTION;
auto dropdownIndex = 0;
for (auto i = 0; i < std::min(numItems, Dropdown::ItemsMaxSize); i++)
{
gDropdownItems[i].Format = STR_DROPDOWN_MENU_LABEL;
gDropdownItems[i].Args = (static_cast<int64_t>(i + 1) << 32)
if (ride->vehicleColourSettings == VehicleColourSettings::perCar)
{
const auto& carEntry = rideEntry->Cars[RideEntryGetVehicleAtPosition(
ride->subtype, ride->num_cars_per_train, i)];
if (!carEntry.isVisible())
{
continue;
}
}
int64_t vehicleIndex = dropdownIndex + 1;
gDropdownItems[dropdownIndex].Format = STR_DROPDOWN_MENU_LABEL;
gDropdownItems[dropdownIndex].Args = (vehicleIndex << 32)
| ((GetRideComponentName(ride->GetRideTypeDescriptor().NameConvention.vehicle).capitalised) << 16)
| stringId;
dropdownIndex++;
}
WindowDropdownShowTextCustomWidth(
{ windowPos.x + dropdownWidget->left, windowPos.y + dropdownWidget->top }, dropdownWidget->height() + 1,
colours[1], 0, Dropdown::Flag::StayOpen, numItems, widgets[widgetIndex].right - dropdownWidget->left);
colours[1], 0, Dropdown::Flag::StayOpen, dropdownIndex,
widgets[widgetIndex].right - dropdownWidget->left);
Dropdown::SetChecked(_vehicleIndex, true);
Dropdown::SetChecked(carIndexToDropdownIndex(_vehicleIndex), true);
break;
}
case WIDX_VEHICLE_BODY_COLOUR:
@@ -4423,12 +4528,17 @@ namespace OpenRCT2::Ui::Windows
{
auto rideSetAppearanceAction = RideSetAppearanceAction(
rideId, RideSetAppearanceType::VehicleColourScheme, dropdownIndex, 0);
rideSetAppearanceAction.SetCallback([this](const GameAction* ga, const GameActions::Result* result) {
if (result->Error == GameActions::Status::Ok)
{
ResetVehicleIndex();
}
});
GameActions::Execute(&rideSetAppearanceAction);
_vehicleIndex = 0;
break;
}
break;
case WIDX_VEHICLE_COLOUR_INDEX_DROPDOWN:
_vehicleIndex = dropdownIndex;
_vehicleIndex = dropdownIndexToCarIndex(dropdownIndex);
Invalidate();
break;
case WIDX_VEHICLE_BODY_COLOUR:
@@ -4692,7 +4802,7 @@ namespace OpenRCT2::Ui::Windows
ft.Add<StringId>(VehicleColourSchemeNames[EnumValue(ride->vehicleColourSettings)]);
ft.Add<StringId>(GetRideComponentName(ride->GetRideTypeDescriptor().NameConvention.vehicle).singular);
ft.Add<StringId>(GetRideComponentName(ride->GetRideTypeDescriptor().NameConvention.vehicle).capitalised);
ft.Add<uint16_t>(_vehicleIndex + 1);
ft.Add<uint16_t>(carIndexToDropdownIndex(_vehicleIndex) + 1);
// Vehicle index
if (ride->vehicleColourSettings != VehicleColourSettings::same)

View File

@@ -138,3 +138,8 @@ void CarEntrySetImageMaxSizes(CarEntry& carEntry, int32_t numImages)
carEntry.sprite_height_negative = spriteHeightNegative;
carEntry.sprite_height_positive = spriteHeightPositive;
}
bool CarEntry::isVisible() const
{
return TabRotationMask != 0;
}

View File

@@ -226,6 +226,8 @@ struct CarEntry
bool GroupEnabled(SpriteGroupType rotationType) const;
uint32_t GroupImageId(SpriteGroupType spriteGroup) const;
uint32_t SpriteOffset(SpriteGroupType spriteGroup, int32_t imageDirection, uint8_t rankIndex) const;
bool isVisible() const;
};
void CarEntrySetImageMaxSizes(CarEntry& carEntry, int32_t numImages);