diff --git a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp index e9daf838e8..a4fa7d0b73 100644 --- a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp +++ b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp @@ -350,7 +350,7 @@ static void window_editor_objective_options_set_page(rct_window* w, int32_t page */ static void window_editor_objective_options_set_objective(rct_window* w, int32_t objective) { - gScenarioObjectiveType = objective; + gScenarioObjective.Type = objective; w->Invalidate(); // Set default objective arguments @@ -362,30 +362,30 @@ static void window_editor_objective_options_set_objective(rct_window* w, int32_t case OBJECTIVE_10_ROLLERCOASTERS: break; case OBJECTIVE_GUESTS_BY: - gScenarioObjectiveYear = 3; - gScenarioObjectiveNumGuests = 1500; + gScenarioObjective.Year = 3; + gScenarioObjective.NumGuests = 1500; break; case OBJECTIVE_PARK_VALUE_BY: - gScenarioObjectiveYear = 3; - gScenarioObjectiveCurrency = MONEY(50000, 00); + gScenarioObjective.Year = 3; + gScenarioObjective.Currency = MONEY(50000, 00); break; case OBJECTIVE_GUESTS_AND_RATING: - gScenarioObjectiveNumGuests = 2000; + gScenarioObjective.NumGuests = 2000; break; case OBJECTIVE_MONTHLY_RIDE_INCOME: - gScenarioObjectiveCurrency = MONEY(10000, 00); + gScenarioObjective.Currency = MONEY(10000, 00); break; case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: - gScenarioObjectiveNumGuests = 1200; + gScenarioObjective.MinimumLength = 1200; break; case OBJECTIVE_FINISH_5_ROLLERCOASTERS: - gScenarioObjectiveCurrency = FIXED_2DP(6, 70); + gScenarioObjective.MinimumExcitement = FIXED_2DP(6, 70); break; case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: - gScenarioObjectiveCurrency = MONEY(50000, 00); + gScenarioObjective.Currency = MONEY(50000, 00); break; case OBJECTIVE_MONTHLY_FOOD_INCOME: - gScenarioObjectiveCurrency = MONEY(1000, 00); + gScenarioObjective.Currency = MONEY(1000, 00); break; } } @@ -459,7 +459,7 @@ static void window_editor_objective_options_show_objective_dropdown(rct_window* { w->windowPos.x + dropdownWidget->left, w->windowPos.y + dropdownWidget->top }, dropdownWidget->height() + 1, w->colours[1], 0, DROPDOWN_FLAG_STAY_OPEN, numItems, dropdownWidget->width() - 3); - objectiveType = gScenarioObjectiveType; + objectiveType = gScenarioObjective.Type; for (int32_t j = 0; j < numItems; j++) { if (gDropdownItemsArgs[j] - STR_OBJECTIVE_DROPDOWN_NONE == objectiveType) @@ -490,62 +490,62 @@ static void window_editor_objective_options_show_category_dropdown(rct_window* w static void window_editor_objective_options_arg_1_increase(rct_window* w) { - switch (gScenarioObjectiveType) + switch (gScenarioObjective.Type) { case OBJECTIVE_PARK_VALUE_BY: case OBJECTIVE_MONTHLY_RIDE_INCOME: case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: - if (gScenarioObjectiveCurrency >= MONEY(2000000, 00)) + if (gScenarioObjective.Currency >= MONEY(2000000, 00)) { context_show_error(STR_CANT_INCREASE_FURTHER, STR_NONE); } else { - gScenarioObjectiveCurrency += MONEY(1000, 0); + gScenarioObjective.Currency += MONEY(1000, 0); w->Invalidate(); } break; case OBJECTIVE_MONTHLY_FOOD_INCOME: - if (gScenarioObjectiveCurrency >= MONEY(2000000, 00)) + if (gScenarioObjective.Currency >= MONEY(2000000, 00)) { context_show_error(STR_CANT_INCREASE_FURTHER, STR_NONE); } else { - gScenarioObjectiveCurrency += MONEY(100, 0); + gScenarioObjective.Currency += MONEY(100, 0); w->Invalidate(); } break; case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: - if (gScenarioObjectiveNumGuests >= 5000) + if (gScenarioObjective.MinimumLength >= 5000) { context_show_error(STR_CANT_INCREASE_FURTHER, STR_NONE); } else { - gScenarioObjectiveNumGuests += 100; + gScenarioObjective.MinimumLength += 100; w->Invalidate(); } break; case OBJECTIVE_FINISH_5_ROLLERCOASTERS: - if (gScenarioObjectiveCurrency >= FIXED_2DP(9, 90)) + if (gScenarioObjective.MinimumExcitement >= FIXED_2DP(9, 90)) { context_show_error(STR_CANT_INCREASE_FURTHER, STR_NONE); } else { - gScenarioObjectiveCurrency += FIXED_2DP(0, 10); + gScenarioObjective.MinimumExcitement += FIXED_2DP(0, 10); w->Invalidate(); } break; default: - if (gScenarioObjectiveNumGuests >= 5000) + if (gScenarioObjective.NumGuests >= 5000) { context_show_error(STR_CANT_INCREASE_FURTHER, STR_NONE); } else { - gScenarioObjectiveNumGuests += 50; + gScenarioObjective.NumGuests += 50; w->Invalidate(); } break; @@ -554,62 +554,62 @@ static void window_editor_objective_options_arg_1_increase(rct_window* w) static void window_editor_objective_options_arg_1_decrease(rct_window* w) { - switch (gScenarioObjectiveType) + switch (gScenarioObjective.Type) { case OBJECTIVE_PARK_VALUE_BY: case OBJECTIVE_MONTHLY_RIDE_INCOME: case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: - if (gScenarioObjectiveCurrency <= MONEY(1000, 00)) + if (gScenarioObjective.Currency <= MONEY(1000, 00)) { context_show_error(STR_CANT_REDUCE_FURTHER, STR_NONE); } else { - gScenarioObjectiveCurrency -= MONEY(1000, 0); + gScenarioObjective.Currency -= MONEY(1000, 0); w->Invalidate(); } break; case OBJECTIVE_MONTHLY_FOOD_INCOME: - if (gScenarioObjectiveCurrency <= MONEY(1000, 00)) + if (gScenarioObjective.Currency <= MONEY(1000, 00)) { context_show_error(STR_CANT_REDUCE_FURTHER, STR_NONE); } else { - gScenarioObjectiveCurrency -= MONEY(100, 0); + gScenarioObjective.Currency -= MONEY(100, 0); w->Invalidate(); } break; case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: - if (gScenarioObjectiveNumGuests <= 1000) + if (gScenarioObjective.MinimumLength <= 1000) { context_show_error(STR_CANT_REDUCE_FURTHER, STR_NONE); } else { - gScenarioObjectiveNumGuests -= 100; + gScenarioObjective.MinimumLength -= 100; w->Invalidate(); } break; case OBJECTIVE_FINISH_5_ROLLERCOASTERS: - if (gScenarioObjectiveCurrency <= FIXED_2DP(4, 00)) + if (gScenarioObjective.MinimumExcitement <= FIXED_2DP(4, 00)) { context_show_error(STR_CANT_REDUCE_FURTHER, STR_NONE); } else { - gScenarioObjectiveCurrency -= FIXED_2DP(0, 10); + gScenarioObjective.MinimumExcitement -= FIXED_2DP(0, 10); w->Invalidate(); } break; default: - if (gScenarioObjectiveNumGuests <= 250) + if (gScenarioObjective.NumGuests <= 250) { context_show_error(STR_CANT_REDUCE_FURTHER, STR_NONE); } else { - gScenarioObjectiveNumGuests -= 50; + gScenarioObjective.NumGuests -= 50; w->Invalidate(); } break; @@ -618,26 +618,26 @@ static void window_editor_objective_options_arg_1_decrease(rct_window* w) static void window_editor_objective_options_arg_2_increase(rct_window* w) { - if (gScenarioObjectiveYear >= 25) + if (gScenarioObjective.Year >= 25) { context_show_error(STR_CANT_INCREASE_FURTHER, STR_NONE); } else { - gScenarioObjectiveYear++; + gScenarioObjective.Year++; w->Invalidate(); } } static void window_editor_objective_options_arg_2_decrease(rct_window* w) { - if (gScenarioObjectiveYear <= 1) + if (gScenarioObjective.Year <= 1) { context_show_error(STR_CANT_REDUCE_FURTHER, STR_NONE); } else { - gScenarioObjectiveYear--; + gScenarioObjective.Year--; w->Invalidate(); } } @@ -687,7 +687,7 @@ static void window_editor_objective_options_main_dropdown(rct_window* w, rct_wid case WIDX_OBJECTIVE_DROPDOWN: // TODO: Don't rely on string ID order newObjectiveType = static_cast(gDropdownItemsArgs[dropdownIndex] - STR_OBJECTIVE_DROPDOWN_NONE); - if (gScenarioObjectiveType != newObjectiveType) + if (gScenarioObjective.Type != newObjectiveType) window_editor_objective_options_set_objective(w, newObjectiveType); break; case WIDX_CATEGORY_DROPDOWN: @@ -714,7 +714,7 @@ static void window_editor_objective_options_main_update(rct_window* w) widget_invalidate(w, WIDX_TAB_1); parkFlags = gParkFlags; - objectiveType = gScenarioObjectiveType; + objectiveType = gScenarioObjective.Type; // Check if objective is allowed by money and pay-per-ride settings. const bool objectiveAllowedByMoneyUsage = !(parkFlags & PARK_FLAGS_NO_MONEY_SCENARIO) @@ -778,7 +778,7 @@ static void window_editor_objective_options_main_invalidate(rct_window* w) window_editor_objective_options_set_pressed_tab(w); - switch (gScenarioObjectiveType) + switch (gScenarioObjective.Type) { case OBJECTIVE_GUESTS_BY: case OBJECTIVE_PARK_VALUE_BY: @@ -838,14 +838,14 @@ static void window_editor_objective_options_main_paint(rct_window* w, rct_drawpi // Objective value screenCoords = w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_OBJECTIVE].left + 1, w->widgets[WIDX_OBJECTIVE].top }; - stringId = ObjectiveDropdownOptionNames[gScenarioObjectiveType]; + stringId = ObjectiveDropdownOptionNames[gScenarioObjective.Type]; gfx_draw_string_left(dpi, STR_WINDOW_COLOUR_2_STRINGID, &stringId, COLOUR_BLACK, screenCoords); if (w->widgets[WIDX_OBJECTIVE_ARG_1].type != WWT_EMPTY) { // Objective argument 1 label screenCoords = w->windowPos + ScreenCoordsXY{ 28, w->widgets[WIDX_OBJECTIVE_ARG_1].top }; - switch (gScenarioObjectiveType) + switch (gScenarioObjective.Type) { case OBJECTIVE_GUESTS_BY: case OBJECTIVE_GUESTS_AND_RATING: @@ -873,27 +873,27 @@ static void window_editor_objective_options_main_paint(rct_window* w, rct_drawpi // Objective argument 1 value screenCoords = w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_OBJECTIVE_ARG_1].left + 1, w->widgets[WIDX_OBJECTIVE_ARG_1].top }; - switch (gScenarioObjectiveType) + switch (gScenarioObjective.Type) { case OBJECTIVE_GUESTS_BY: case OBJECTIVE_GUESTS_AND_RATING: stringId = STR_WINDOW_OBJECTIVE_VALUE_GUEST_COUNT; - arg = gScenarioObjectiveNumGuests; + arg = gScenarioObjective.NumGuests; break; case OBJECTIVE_PARK_VALUE_BY: case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: case OBJECTIVE_MONTHLY_RIDE_INCOME: case OBJECTIVE_MONTHLY_FOOD_INCOME: stringId = STR_CURRENCY_FORMAT_LABEL; - arg = gScenarioObjectiveCurrency; + arg = gScenarioObjective.Currency; break; case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: stringId = STR_WINDOW_OBJECTIVE_VALUE_LENGTH; - arg = gScenarioObjectiveNumGuests; + arg = gScenarioObjective.MinimumLength; break; default: stringId = STR_WINDOW_OBJECTIVE_VALUE_RATING; - arg = gScenarioObjectiveCurrency; + arg = gScenarioObjective.Currency; break; } gfx_draw_string_left(dpi, stringId, &arg, COLOUR_BLACK, screenCoords); @@ -908,7 +908,7 @@ static void window_editor_objective_options_main_paint(rct_window* w, rct_drawpi // Objective argument 2 value screenCoords = w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_OBJECTIVE_ARG_2].left + 1, w->widgets[WIDX_OBJECTIVE_ARG_2].top }; - arg = (gScenarioObjectiveYear * MONTH_COUNT) - 1; + arg = (gScenarioObjective.Year * MONTH_COUNT) - 1; gfx_draw_string_left(dpi, STR_WINDOW_OBJECTIVE_VALUE_DATE, &arg, COLOUR_BLACK, screenCoords); } diff --git a/src/openrct2-ui/windows/Finances.cpp b/src/openrct2-ui/windows/Finances.cpp index 031bc99dcd..ac60e99efb 100644 --- a/src/openrct2-ui/windows/Finances.cpp +++ b/src/openrct2-ui/windows/Finances.cpp @@ -703,7 +703,7 @@ static void window_finances_summary_paint(rct_window* w, rct_drawpixelinfo* dpi) gfx_draw_string_left(dpi, stringId, &gCash, COLOUR_BLACK, w->windowPos + ScreenCoordsXY{ 8, 294 }); // Objective related financial information - if (gScenarioObjectiveType == OBJECTIVE_MONTHLY_FOOD_INCOME) + if (gScenarioObjective.Type == OBJECTIVE_MONTHLY_FOOD_INCOME) { money32 lastMonthProfit = finance_get_last_month_shop_profit(); ft = Formatter::Common(); diff --git a/src/openrct2-ui/windows/Park.cpp b/src/openrct2-ui/windows/Park.cpp index e55f46d4a6..82b7663e6f 100644 --- a/src/openrct2-ui/windows/Park.cpp +++ b/src/openrct2-ui/windows/Park.cpp @@ -789,7 +789,7 @@ static void window_park_entrance_invalidate(rct_window* w) + widget_is_pressed(w, WIDX_OPEN_LIGHT); // Only allow closing of park for guest / rating objective - if (gScenarioObjectiveType == OBJECTIVE_GUESTS_AND_RATING) + if (gScenarioObjective.Type == OBJECTIVE_GUESTS_AND_RATING) w->disabled_widgets |= (1 << WIDX_OPEN_OR_CLOSE) | (1 << WIDX_CLOSE_LIGHT) | (1 << WIDX_OPEN_LIGHT); else w->disabled_widgets &= ~((1 << WIDX_OPEN_OR_CLOSE) | (1 << WIDX_CLOSE_LIGHT) | (1 << WIDX_OPEN_LIGHT)); @@ -813,7 +813,7 @@ static void window_park_entrance_invalidate(rct_window* w) if (theme_get_flags() & UITHEME_FLAG_USE_LIGHTS_PARK) { window_park_entrance_widgets[WIDX_OPEN_OR_CLOSE].type = WWT_EMPTY; - if (gScenarioObjectiveType == OBJECTIVE_GUESTS_AND_RATING) + if (gScenarioObjective.Type == OBJECTIVE_GUESTS_AND_RATING) { window_park_entrance_widgets[WIDX_CLOSE_LIGHT].type = WWT_FLATBTN; window_park_entrance_widgets[WIDX_OPEN_LIGHT].type = WWT_FLATBTN; @@ -1610,10 +1610,10 @@ static void window_park_objective_paint(rct_window* w, rct_drawpixelinfo* dpi) // Objective ft = Formatter::Common(); - if (gScenarioObjectiveType == OBJECTIVE_BUILD_THE_BEST) + if (gScenarioObjective.Type == OBJECTIVE_BUILD_THE_BEST) { rct_string_id rideTypeString = STR_NONE; - auto rideTypeId = gScenarioObjectiveNumGuests; + auto rideTypeId = gScenarioObjective.RideId; if (rideTypeId != RIDE_TYPE_NULL && rideTypeId < RIDE_TYPE_COUNT) { rideTypeString = RideTypeDescriptors[rideTypeId].Naming.Name; @@ -1622,13 +1622,13 @@ static void window_park_objective_paint(rct_window* w, rct_drawpixelinfo* dpi) } else { - ft.Add(gScenarioObjectiveNumGuests); - ft.Add(date_get_total_months(MONTH_OCTOBER, gScenarioObjectiveYear)); - ft.Add(gScenarioObjectiveCurrency); + ft.Add(gScenarioObjective.NumGuests); + ft.Add(date_get_total_months(MONTH_OCTOBER, gScenarioObjective.Year)); + ft.Add(gScenarioObjective.Currency); } screenCoords.y += gfx_draw_string_left_wrapped( - dpi, gCommonFormatArgs, screenCoords, 221, ObjectiveNames[gScenarioObjectiveType], COLOUR_BLACK); + dpi, gCommonFormatArgs, screenCoords, 221, ObjectiveNames[gScenarioObjective.Type], COLOUR_BLACK); screenCoords.y += 5; // Objective outcome diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index 33156e953b..7948f6eafd 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -130,10 +130,10 @@ namespace Editor safe_strcpy(gS6Info.name, gScenarioName.c_str(), sizeof(gS6Info.name)); safe_strcpy(gS6Info.details, gScenarioDetails.c_str(), sizeof(gS6Info.details)); - gS6Info.objective_type = gScenarioObjectiveType; - gS6Info.objective_arg_1 = gScenarioObjectiveYear; - gS6Info.objective_arg_2 = gScenarioObjectiveCurrency; - gS6Info.objective_arg_3 = gScenarioObjectiveNumGuests; + gS6Info.objective_type = gScenarioObjective.Type; + gS6Info.objective_arg_1 = gScenarioObjective.Year; + gS6Info.objective_arg_2 = gScenarioObjective.Currency; + gS6Info.objective_arg_3 = gScenarioObjective.NumGuests; climate_reset(gClimate); gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR; diff --git a/src/openrct2/actions/RideCreateAction.hpp b/src/openrct2/actions/RideCreateAction.hpp index f8f3240b9f..ee9b773a4e 100644 --- a/src/openrct2/actions/RideCreateAction.hpp +++ b/src/openrct2/actions/RideCreateAction.hpp @@ -229,7 +229,7 @@ public: ride->price[1] = ShopItems[rideEntry->shop_item[1]].DefaultPrice; } - if (gScenarioObjectiveType == OBJECTIVE_BUILD_THE_BEST) + if (gScenarioObjective.Type == OBJECTIVE_BUILD_THE_BEST) { ride->price[0] = 0; } diff --git a/src/openrct2/actions/SetCheatAction.hpp b/src/openrct2/actions/SetCheatAction.hpp index 297597c690..124abb6578 100644 --- a/src/openrct2/actions/SetCheatAction.hpp +++ b/src/openrct2/actions/SetCheatAction.hpp @@ -219,7 +219,7 @@ public: ParkSetOpen(!park_is_open()); break; case CheatType::HaveFun: - gScenarioObjectiveType = OBJECTIVE_HAVE_FUN; + gScenarioObjective.Type = OBJECTIVE_HAVE_FUN; break; case CheatType::SetForcedParkRating: set_forced_park_rating(_param1); diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index a1242661a3..74958829ea 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -2715,21 +2715,21 @@ private: void ImportScenarioObjective() { - gScenarioObjectiveType = _s4.scenario_objective_type; - gScenarioObjectiveYear = _s4.scenario_objective_years; - gScenarioObjectiveNumGuests = _s4.scenario_objective_num_guests; + gScenarioObjective.Type = _s4.scenario_objective_type; + gScenarioObjective.Year = _s4.scenario_objective_years; + gScenarioObjective.NumGuests = _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. if (_s4.scenario_objective_type == OBJECTIVE_PARK_VALUE_BY) - gScenarioObjectiveCurrency = CorrectRCT1ParkValue(_s4.scenario_objective_currency); + gScenarioObjective.Currency = CorrectRCT1ParkValue(_s4.scenario_objective_currency); else - gScenarioObjectiveCurrency = _s4.scenario_objective_currency; + gScenarioObjective.Currency = _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(); + gScenarioObjective.RideId = GetBuildTheBestRideId(); } void ImportSavedView() diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index 42122d8efe..5da890454d 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -272,16 +272,17 @@ void S6Exporter::Export() _s6.guest_initial_cash = gGuestInitialCash; _s6.guest_initial_hunger = gGuestInitialHunger; _s6.guest_initial_thirst = gGuestInitialThirst; - _s6.objective_type = gScenarioObjectiveType; - _s6.objective_year = gScenarioObjectiveYear; + _s6.objective_type = gScenarioObjective.Type; + _s6.objective_year = gScenarioObjective.Year; // pad_013580FA - _s6.objective_currency = gScenarioObjectiveCurrency; + _s6.objective_currency = gScenarioObjective.Currency; // 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; + if (gScenarioObjective.Type == OBJECTIVE_BUILD_THE_BEST) + _s6.objective_guests = gScenarioObjective.RideId + RCT2_RIDE_STRING_START; else - _s6.objective_guests = gScenarioObjectiveNumGuests; + _s6.objective_guests = gScenarioObjective.NumGuests; + 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 827be11249..7195390148 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -292,16 +292,16 @@ public: gGuestInitialCash = _s6.guest_initial_cash; gGuestInitialHunger = _s6.guest_initial_hunger; gGuestInitialThirst = _s6.guest_initial_thirst; - gScenarioObjectiveType = _s6.objective_type; - gScenarioObjectiveYear = _s6.objective_year; + gScenarioObjective.Type = _s6.objective_type; + gScenarioObjective.Year = _s6.objective_year; // pad_013580FA - gScenarioObjectiveCurrency = _s6.objective_currency; + gScenarioObjective.Currency = _s6.objective_currency; // 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; + if (gScenarioObjective.Type == OBJECTIVE_BUILD_THE_BEST) + gScenarioObjective.RideId = _s6.objective_guests - RCT2_RIDE_STRING_START; else - gScenarioObjectiveNumGuests = _s6.objective_guests; + gScenarioObjective.NumGuests = _s6.objective_guests; ImportMarketingCampaigns(); gCurrentExpenditure = _s6.current_expenditure; diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 9bec767e34..b61f9a427a 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -71,10 +71,7 @@ uint32_t gLastAutoSaveUpdate = 0; uint32_t gScenarioTicks; random_engine_t gScenarioRand; -uint8_t gScenarioObjectiveType; -uint8_t gScenarioObjectiveYear; -uint16_t gScenarioObjectiveNumGuests; -money32 gScenarioObjectiveCurrency; +Objective gScenarioObjective; uint16_t gScenarioParkRatingWarningDays; money32 gScenarioCompletedCompanyValue; @@ -100,7 +97,7 @@ void scenario_begin() research_reset_current_item(); scenery_set_default_placement_configuration(); News::InitQueue(); - if (gScenarioObjectiveType != OBJECTIVE_NONE && !gLoadKeepWindowsOpen) + if (gScenarioObjective.Type != OBJECTIVE_NONE && !gLoadKeepWindowsOpen) context_open_window_view(WV_PARK_OBJECTIVE); auto& park = GetContext()->GetGameState()->GetPark(); @@ -291,7 +288,7 @@ static void scenario_day_update() { finance_update_daily_profit(); peep_update_days_in_queue(); - switch (gScenarioObjectiveType) + switch (gScenarioObjective.Type) { case OBJECTIVE_10_ROLLERCOASTERS: case OBJECTIVE_GUESTS_AND_RATING: @@ -528,7 +525,7 @@ uint32_t scenario_rand_max(uint32_t max) */ static bool scenario_prepare_rides_for_save() { - int32_t isFiveCoasterObjective = gScenarioObjectiveType == OBJECTIVE_FINISH_5_ROLLERCOASTERS; + int32_t isFiveCoasterObjective = gScenarioObjective.Type == OBJECTIVE_FINISH_5_ROLLERCOASTERS; uint8_t rcs = 0; for (auto& ride : GetRideManager()) @@ -595,10 +592,10 @@ bool scenario_prepare_for_save() if (gS6Info.name[0] == 0) String::Set(gS6Info.name, sizeof(gS6Info.name), parkName); - gS6Info.objective_type = gScenarioObjectiveType; - gS6Info.objective_arg_1 = gScenarioObjectiveYear; - gS6Info.objective_arg_2 = gScenarioObjectiveCurrency; - gS6Info.objective_arg_3 = gScenarioObjectiveNumGuests; + gS6Info.objective_type = gScenarioObjective.Type; + gS6Info.objective_arg_1 = gScenarioObjective.Year; + gS6Info.objective_arg_2 = gScenarioObjective.Currency; + gS6Info.objective_arg_3 = gScenarioObjective.NumGuests; // This can return false if the goal is 'Finish 5 roller coaster' and there are too few. if (!scenario_prepare_rides_for_save()) @@ -606,7 +603,7 @@ bool scenario_prepare_for_save() return false; } - if (gScenarioObjectiveType == OBJECTIVE_GUESTS_AND_RATING) + if (gScenarioObjective.Type == OBJECTIVE_GUESTS_AND_RATING) gParkFlags |= PARK_FLAGS_PARK_OPEN; // Fix #2385: saved scenarios did not initialise temperatures to selected climate @@ -711,43 +708,45 @@ void scenario_remove_trackless_rides(rct_s6_data* s6) } } -static void scenario_objective_check_guests_by() +ObjectiveStatus Objective::CheckGuestsBy() const { - uint8_t objectiveYear = gScenarioObjectiveYear; int16_t parkRating = gParkRating; int32_t currentMonthYear = gDateMonthsElapsed; - if (currentMonthYear == MONTH_COUNT * objectiveYear || gConfigGeneral.allow_early_completion) + if (currentMonthYear == MONTH_COUNT * Year || gConfigGeneral.allow_early_completion) { - if (parkRating >= 600 && gNumGuestsInPark >= gScenarioObjectiveNumGuests) + if (parkRating >= 600 && gNumGuestsInPark >= NumGuests) { - scenario_success(); + return ObjectiveStatus::Success; } - else if (currentMonthYear == MONTH_COUNT * objectiveYear) + else if (currentMonthYear == MONTH_COUNT * Year) { - scenario_failure(); + return ObjectiveStatus::Failure; } } + + return ObjectiveStatus::Undecided; } -static void scenario_objective_check_park_value_by() +ObjectiveStatus Objective::CheckParkValueBy() const { - uint8_t objectiveYear = gScenarioObjectiveYear; int32_t currentMonthYear = gDateMonthsElapsed; - money32 objectiveParkValue = gScenarioObjectiveCurrency; + money32 objectiveParkValue = Currency; money32 parkValue = gParkValue; - if (currentMonthYear == MONTH_COUNT * objectiveYear || gConfigGeneral.allow_early_completion) + if (currentMonthYear == MONTH_COUNT * Year || gConfigGeneral.allow_early_completion) { if (parkValue >= objectiveParkValue) { - scenario_success(); + return ObjectiveStatus::Success; } - else if (currentMonthYear == MONTH_COUNT * objectiveYear) + else if (currentMonthYear == MONTH_COUNT * Year) { - scenario_failure(); + return ObjectiveStatus::Failure; } } + + return ObjectiveStatus::Undecided; } /** @@ -755,7 +754,7 @@ static void scenario_objective_check_park_value_by() * excitement >= 600 . * rct2: **/ -static void scenario_objective_check_10_rollercoasters() +ObjectiveStatus Objective::Check10RollerCoasters() const { auto rcs = 0; std::bitset type_already_counted; @@ -776,15 +775,17 @@ static void scenario_objective_check_10_rollercoasters() } if (rcs >= 10) { - scenario_success(); + return ObjectiveStatus::Success; } + + return ObjectiveStatus::Undecided; } /** * * rct2: 0x0066A13C */ -static void scenario_objective_check_guests_and_rating() +ObjectiveStatus Objective::CheckGuestsAndRating() const { if (gParkRating < 700 && gDateMonthsElapsed >= 1) { @@ -821,8 +822,8 @@ static void scenario_objective_check_guests_and_rating() { News::AddItemToQueue(News::ItemType::Graph, STR_PARK_HAS_BEEN_CLOSED_DOWN, 0); gParkFlags &= ~PARK_FLAGS_PARK_OPEN; - scenario_failure(); gGuestInitialHappiness = 50; + return ObjectiveStatus::Failure; } } else if (gScenarioCompletedCompanyValue != COMPANY_VALUE_ON_FAILED_OBJECTIVE) @@ -831,17 +832,21 @@ static void scenario_objective_check_guests_and_rating() } if (gParkRating >= 700) - if (gNumGuestsInPark >= gScenarioObjectiveNumGuests) - scenario_success(); + if (gNumGuestsInPark >= NumGuests) + return ObjectiveStatus::Success; + + return ObjectiveStatus::Undecided; } -static void scenario_objective_check_monthly_ride_income() +ObjectiveStatus Objective::CheckMonthlyRideIncome() const { money32 lastMonthRideIncome = gExpenditureTable[1][static_cast(ExpenditureType::ParkRideTickets)]; - if (lastMonthRideIncome >= gScenarioObjectiveCurrency) + if (lastMonthRideIncome >= Currency) { - scenario_success(); + return ObjectiveStatus::Success; } + + return ObjectiveStatus::Undecided; } /** @@ -849,9 +854,8 @@ static void scenario_objective_check_monthly_ride_income() * excitement > 700 and a minimum length; * rct2: 0x0066A6B5 */ -static void scenario_objective_check_10_rollercoasters_length() +ObjectiveStatus Objective::Check10RollerCoastersLength() const { - const auto objective_length = gScenarioObjectiveNumGuests; std::bitset type_already_counted; auto rcs = 0; for (const auto& ride : GetRideManager()) @@ -863,7 +867,7 @@ static void scenario_objective_check_10_rollercoasters_length() { if (ride_entry_has_category(rideEntry, RIDE_CATEGORY_ROLLERCOASTER) && !type_already_counted[ride.subtype]) { - if ((ride_get_total_length(&ride) >> 16) > objective_length) + if ((ride_get_total_length(&ride) >> 16) > MinimumLength) { type_already_counted[ride.subtype] = true; rcs++; @@ -874,20 +878,20 @@ static void scenario_objective_check_10_rollercoasters_length() } if (rcs >= 10) { - scenario_success(); + return ObjectiveStatus::Success; } + + return ObjectiveStatus::Undecided; } -static void scenario_objective_check_finish_5_rollercoasters() +ObjectiveStatus Objective::CheckFinish5RollerCoasters() const { - const auto objectiveRideExcitement = gScenarioObjectiveCurrency; - // Originally, this did not check for null rides, neither did it check if // the rides are even rollercoasters, never mind the right rollercoasters to be finished. auto rcs = 0; for (const auto& ride : GetRideManager()) { - if (ride.status != RIDE_STATUS_CLOSED && ride.excitement >= objectiveRideExcitement) + if (ride.status != RIDE_STATUS_CLOSED && ride.excitement >= MinimumExcitement) { auto rideEntry = ride.GetRideEntry(); if (rideEntry != nullptr) @@ -902,21 +906,26 @@ static void scenario_objective_check_finish_5_rollercoasters() } if (rcs >= 5) { - scenario_success(); + return ObjectiveStatus::Success; } + + return ObjectiveStatus::Undecided; } -static void scenario_objective_check_replay_loan_and_park_value() +ObjectiveStatus Objective::CheckRepayLoanAndParkValue() const { - money32 objectiveParkValue = gScenarioObjectiveCurrency; money32 parkValue = gParkValue; money32 currentLoan = gBankLoan; - if (currentLoan <= 0 && parkValue >= objectiveParkValue) - scenario_success(); + if (currentLoan <= 0 && parkValue >= Currency) + { + return ObjectiveStatus::Success; + } + + return ObjectiveStatus::Undecided; } -static void scenario_objective_check_monthly_food_income() +ObjectiveStatus Objective::CheckMonthlyFoodIncome() const { money32* lastMonthExpenditure = gExpenditureTable[1]; int32_t lastMonthProfit = lastMonthExpenditure[static_cast(ExpenditureType::ShopSales)] @@ -924,53 +933,61 @@ static void scenario_objective_check_monthly_food_income() + lastMonthExpenditure[static_cast(ExpenditureType::FoodDrinkSales)] + lastMonthExpenditure[static_cast(ExpenditureType::FoodDrinkStock)]; - if (lastMonthProfit >= gScenarioObjectiveCurrency) + if (lastMonthProfit >= Currency) + { + return ObjectiveStatus::Success; + } + + return ObjectiveStatus::Undecided; +} + +static void scenario_objective_check() +{ + auto status = gScenarioObjective.Check(); + if (status == ObjectiveStatus::Success) { scenario_success(); } + else if (status == ObjectiveStatus::Failure) + { + scenario_failure(); + } } /** * Checks the win/lose conditions of the current objective. * rct2: 0x0066A4B2 */ -static void scenario_objective_check() +ObjectiveStatus Objective::Check() const { if (gScenarioCompletedCompanyValue != MONEY32_UNDEFINED) { - return; + return ObjectiveStatus::Undecided; } - switch (gScenarioObjectiveType) + switch (Type) { case OBJECTIVE_GUESTS_BY: - scenario_objective_check_guests_by(); - break; + return CheckGuestsBy(); case OBJECTIVE_PARK_VALUE_BY: - scenario_objective_check_park_value_by(); - break; + return CheckParkValueBy(); case OBJECTIVE_10_ROLLERCOASTERS: - scenario_objective_check_10_rollercoasters(); - break; + return Check10RollerCoasters(); case OBJECTIVE_GUESTS_AND_RATING: - scenario_objective_check_guests_and_rating(); - break; + return CheckGuestsAndRating(); case OBJECTIVE_MONTHLY_RIDE_INCOME: - scenario_objective_check_monthly_ride_income(); - break; + return CheckMonthlyRideIncome(); case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: - scenario_objective_check_10_rollercoasters_length(); - break; + return Check10RollerCoastersLength(); case OBJECTIVE_FINISH_5_ROLLERCOASTERS: - scenario_objective_check_finish_5_rollercoasters(); - break; + return CheckFinish5RollerCoasters(); case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: - scenario_objective_check_replay_loan_and_park_value(); - break; + return CheckRepayLoanAndParkValue(); case OBJECTIVE_MONTHLY_FOOD_INCOME: - scenario_objective_check_monthly_food_income(); - break; + return CheckMonthlyFoodIncome(); } + + return ObjectiveStatus::Undecided; } bool ObjectiveNeedsMoney(const uint8_t objective) diff --git a/src/openrct2/scenario/Scenario.h b/src/openrct2/scenario/Scenario.h index 51dc1b6533..28f128d910 100644 --- a/src/openrct2/scenario/Scenario.h +++ b/src/openrct2/scenario/Scenario.h @@ -349,6 +349,58 @@ enum OBJECTIVE_COUNT }; +bool ObjectiveNeedsMoney(const uint8_t objective); + +enum class ObjectiveStatus : uint8_t +{ + Undecided, + Success, + Failure, +}; + +struct Objective +{ + uint8_t Type; + uint8_t Year; + union + { + uint16_t NumGuests; + rct_string_id RideId; + uint16_t MinimumLength; // For the "Build 10 coasters of minimum length" objective. + }; + union + { + money32 Currency; + uint16_t MinimumExcitement; // For the "Finish 5 coaster with a minimum excitement rating" objective. + }; + + bool NeedsMoney() const + { + return ObjectiveNeedsMoney(Type); + } + + bool IsValid(bool useMoney, bool canAskMoneyForRides) const + { + const bool objectiveAllowedByMoneyUsage = useMoney || !NeedsMoney(); + // This objective can only work if the player can ask money for rides. + const bool objectiveAllowedByPaymentSettings = (Type != OBJECTIVE_MONTHLY_RIDE_INCOME) || canAskMoneyForRides; + return objectiveAllowedByMoneyUsage && objectiveAllowedByPaymentSettings; + } + + ObjectiveStatus Check() const; + +private: + ObjectiveStatus CheckGuestsBy() const; + ObjectiveStatus CheckParkValueBy() const; + ObjectiveStatus Check10RollerCoasters() const; + ObjectiveStatus CheckGuestsAndRating() const; + ObjectiveStatus CheckMonthlyRideIncome() const; + ObjectiveStatus Check10RollerCoastersLength() const; + ObjectiveStatus CheckFinish5RollerCoasters() const; + ObjectiveStatus CheckRepayLoanAndParkValue() const; + ObjectiveStatus CheckMonthlyFoodIncome() const; +}; + enum { SCENARIO_SELECT_MODE_DIFFICULTY, @@ -375,10 +427,7 @@ extern const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT]; extern uint32_t gScenarioTicks; extern random_engine_t gScenarioRand; -extern uint8_t gScenarioObjectiveType; -extern uint8_t gScenarioObjectiveYear; -extern uint16_t gScenarioObjectiveNumGuests; -extern money32 gScenarioObjectiveCurrency; +extern Objective gScenarioObjective; extern uint16_t gScenarioParkRatingWarningDays; extern money32 gScenarioCompletedCompanyValue; @@ -422,6 +471,5 @@ void scenario_failure(); void scenario_success(); void scenario_success_submit_name(const char* name); void scenario_autosave_check(); -bool ObjectiveNeedsMoney(const uint8_t objective); #endif diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index bea88d46c7..8cb2c70eb3 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -293,9 +293,9 @@ void Park::Initialise() gGuestInitialHappiness = CalculateGuestInitialHappiness(50); gGuestInitialHunger = 200; gGuestInitialThirst = 200; - gScenarioObjectiveType = OBJECTIVE_GUESTS_BY; - gScenarioObjectiveYear = 4; - gScenarioObjectiveNumGuests = 1000; + gScenarioObjective.Type = OBJECTIVE_GUESTS_BY; + gScenarioObjective.Year = 4; + gScenarioObjective.NumGuests = 1000; gLandPrice = MONEY(90, 00); gConstructionRightsPrice = MONEY(40, 00); gParkFlags = PARK_FLAGS_NO_MONEY | PARK_FLAGS_SHOW_REAL_GUEST_NAMES;