diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 8b1c0b9542..8fddd54ced 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -27,6 +27,7 @@ - Fix: [#7006] Submarine Ride is in the wrong research group. - Fix: [#7324] Research window shows vehicle name instead of ride name. - Fix: [#7969, #8175, #12501] When loading a landscape in the Scenario Editor, the inventions list, financial settings and objective settings are reset. +- Fix: [#10549] 'Build the best ride you can' objective missing ride name. - Fix: [#10634] Guests are unable to use uphill paths out of toilets. - Fix: [#10751] Saved mazes are incomplete. - Fix: [#10876] When removing a path, its guest entry point is not removed. diff --git a/src/openrct2-ui/windows/Park.cpp b/src/openrct2-ui/windows/Park.cpp index 31451f5fac..490b953521 100644 --- a/src/openrct2-ui/windows/Park.cpp +++ b/src/openrct2-ui/windows/Park.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1609,9 +1610,22 @@ static void window_park_objective_paint(rct_window* w, rct_drawpixelinfo* dpi) // Objective ft = Formatter::Common(); - ft.Add(gScenarioObjectiveNumGuests); - ft.Add(date_get_total_months(MONTH_OCTOBER, gScenarioObjectiveYear)); - ft.Add(gScenarioObjectiveCurrency); + if (gScenarioObjectiveType == OBJECTIVE_BUILD_THE_BEST) + { + rct_string_id rideTypeString = STR_NONE; + auto rideTypeId = gScenarioObjectiveNumGuests; + if (rideTypeId != RIDE_TYPE_NULL && rideTypeId < RIDE_TYPE_COUNT) + { + rideTypeString = RideTypeDescriptors[rideTypeId].Naming.Name; + } + ft.Add(rideTypeString); + } + else + { + ft.Add(gScenarioObjectiveNumGuests); + ft.Add(date_get_total_months(MONTH_OCTOBER, gScenarioObjectiveYear)); + ft.Add(gScenarioObjectiveCurrency); + } screenCoords.y += gfx_draw_string_left_wrapped( dpi, gCommonFormatArgs, screenCoords, 221, ObjectiveNames[gScenarioObjectiveType], COLOUR_BLACK); diff --git a/src/openrct2-ui/windows/TitleScenarioSelect.cpp b/src/openrct2-ui/windows/TitleScenarioSelect.cpp index 9247fc55cb..78464a6569 100644 --- a/src/openrct2-ui/windows/TitleScenarioSelect.cpp +++ b/src/openrct2-ui/windows/TitleScenarioSelect.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -517,9 +518,22 @@ static void window_scenarioselect_paint(rct_window* w, rct_drawpixelinfo* dpi) // Scenario objective ft = Formatter::Common(); ft.Add(ObjectiveNames[scenario->objective_type]); - ft.Add(scenario->objective_arg_3); - ft.Add(date_get_total_months(MONTH_OCTOBER, scenario->objective_arg_1)); - ft.Add(scenario->objective_arg_2); + if (scenario->objective_type == OBJECTIVE_BUILD_THE_BEST) + { + rct_string_id rideTypeString = STR_NONE; + auto rideTypeId = scenario->objective_arg_3; + if (rideTypeId != RIDE_TYPE_NULL && rideTypeId < RIDE_TYPE_COUNT) + { + rideTypeString = RideTypeDescriptors[rideTypeId].Naming.Name; + } + ft.Add(rideTypeString); + } + else + { + ft.Add(scenario->objective_arg_3); + ft.Add(date_get_total_months(MONTH_OCTOBER, scenario->objective_arg_1)); + ft.Add(scenario->objective_arg_2); + } screenPos.y += gfx_draw_string_left_wrapped(dpi, gCommonFormatArgs, screenPos, 170, STR_OBJECTIVE, COLOUR_BLACK) + 5; // Scenario score diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 089e28f9d0..f23de12696 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -234,6 +234,11 @@ public: else dst->objective_arg_2 = _s4.scenario_objective_currency; dst->objective_arg_3 = _s4.scenario_objective_num_guests; + // This does not seem to be saved in the objective arguments, so look up the ID from the available rides instead. + if (_s4.scenario_objective_type == OBJECTIVE_BUILD_THE_BEST) + { + dst->objective_arg_3 = GetBuildTheBestRideId(); + } auto name = rct2_to_utf8(_s4.scenario_name, RCT2_LANGUAGE_ID_ENGLISH_UK); std::string details; @@ -2713,6 +2718,7 @@ private: gScenarioObjectiveType = _s4.scenario_objective_type; gScenarioObjectiveYear = _s4.scenario_objective_years; gScenarioObjectiveNumGuests = _s4.scenario_objective_num_guests; + // RCT1 used a different way of calculating the park value. // This is corrected here, but since scenario_objective_currency doubles as minimum excitement rating, // we need to check the goal to avoid affecting scenarios like Volcania. @@ -2720,6 +2726,10 @@ private: gScenarioObjectiveCurrency = CorrectRCT1ParkValue(_s4.scenario_objective_currency); else gScenarioObjectiveCurrency = _s4.scenario_objective_currency; + + // This does not seem to be saved in the objective arguments, so look up the ID from the available rides instead. + if (_s4.scenario_objective_type == OBJECTIVE_BUILD_THE_BEST) + gScenarioObjectiveNumGuests = GetBuildTheBestRideId(); } void ImportSavedView() @@ -3121,6 +3131,26 @@ private: } } } + + ObjectEntryIndex GetBuildTheBestRideId() + { + size_t researchListCount; + const rct1_research_item* researchList = GetResearchList(&researchListCount); + for (size_t i = 0; i < researchListCount; i++) + { + if (researchList[i].flags == 0xFF) + { + break; + } + + if (researchList[i].type == RCT1_RESEARCH_TYPE_RIDE) + { + return RCT1::GetRideType(researchList[i].item, 0); + } + } + + return RIDE_TYPE_NULL; + } }; std::unique_ptr ParkImporter::CreateS4() diff --git a/src/openrct2/rct2/RCT2.h b/src/openrct2/rct2/RCT2.h index ec017c8cbc..1e2c4dfa1a 100644 --- a/src/openrct2/rct2/RCT2.h +++ b/src/openrct2/rct2/RCT2.h @@ -52,6 +52,8 @@ constexpr const uint8_t RCT2_MAX_WATER_OBJECTS = 1; constexpr const uint8_t RCT2_MAX_SCENARIO_TEXT_OBJECTS = 1; constexpr const uint8_t RCT2_RIDE_TYPE_COUNT = 91; +constexpr const rct_string_id RCT2_RIDE_STRING_START = 2; + // clang-format off constexpr const uint16_t RCT2_OBJECT_ENTRY_COUNT = RCT2_MAX_RIDE_OBJECTS + diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index 8d6e6543d2..8d14097cd5 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -276,7 +276,12 @@ void S6Exporter::Export() _s6.objective_year = gScenarioObjectiveYear; // pad_013580FA _s6.objective_currency = gScenarioObjectiveCurrency; - _s6.objective_guests = gScenarioObjectiveNumGuests; + // In RCT2, the ride string IDs start at index STR_0002 and are directly mappable. + // This is not always the case in OpenRCT2, so we use the actual ride ID. + if (gScenarioObjectiveType == OBJECTIVE_BUILD_THE_BEST) + _s6.objective_guests = gScenarioObjectiveNumGuests + RCT2_RIDE_STRING_START; + else + _s6.objective_guests = gScenarioObjectiveNumGuests; ExportMarketingCampaigns(); std::memcpy(_s6.balance_history, gCashHistory, sizeof(_s6.balance_history)); diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 1159b198f1..46352866bd 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -296,7 +296,12 @@ public: gScenarioObjectiveYear = _s6.objective_year; // pad_013580FA gScenarioObjectiveCurrency = _s6.objective_currency; - gScenarioObjectiveNumGuests = _s6.objective_guests; + // In RCT2, the ride string IDs start at index STR_0002 and are directly mappable. + // This is not always the case in OpenRCT2, so we use the actual ride ID. + if (gScenarioObjectiveType == OBJECTIVE_BUILD_THE_BEST) + gScenarioObjectiveNumGuests = _s6.objective_guests - RCT2_RIDE_STRING_START; + else + gScenarioObjectiveNumGuests = _s6.objective_guests; ImportMarketingCampaigns(); gCurrentExpenditure = _s6.current_expenditure;