diff --git a/src/openrct2-ui/interface/FileBrowser.cpp b/src/openrct2-ui/interface/FileBrowser.cpp index 6f735c0779..aad357e388 100644 --- a/src/openrct2-ui/interface/FileBrowser.cpp +++ b/src/openrct2-ui/interface/FileBrowser.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/src/openrct2-ui/interface/Objective.cpp b/src/openrct2-ui/interface/Objective.cpp index de1dc0c438..760230a0d1 100644 --- a/src/openrct2-ui/interface/Objective.cpp +++ b/src/openrct2-ui/interface/Objective.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include namespace OpenRCT2::Ui { @@ -33,9 +33,9 @@ namespace OpenRCT2::Ui STR_OBJECTIVE_MONTHLY_FOOD_INCOME, }; - void formatObjective(Formatter& ft, Objective objective) + void formatObjective(Formatter& ft, const Scenario::Objective& objective) { - if (objective.Type == OBJECTIVE_BUILD_THE_BEST) + if (objective.Type == Scenario::ObjectiveType::buildTheBest) { StringId rideTypeString = kStringIdNone; auto rideTypeId = objective.RideId; @@ -45,16 +45,16 @@ namespace OpenRCT2::Ui } ft.Add(rideTypeString); } - else if (objective.Type == OBJECTIVE_GUESTS_BY) + else if (objective.Type == Scenario::ObjectiveType::guestsBy) { ft.Add(objective.NumGuests); ft.Add(DateGetTotalMonths(MONTH_OCTOBER, objective.Year)); } - else if (objective.Type == OBJECTIVE_GUESTS_AND_RATING) + else if (objective.Type == Scenario::ObjectiveType::guestsAndRating) { ft.Add(objective.NumGuests); } - else if (objective.Type == OBJECTIVE_10_ROLLERCOASTERS_LENGTH) + else if (objective.Type == Scenario::ObjectiveType::tenRollercoastersLength) { ft.Add(objective.MinimumLength); } @@ -62,7 +62,7 @@ namespace OpenRCT2::Ui { ft.Add(objective.NumGuests); ft.Add(DateGetTotalMonths(MONTH_OCTOBER, objective.Year)); - if (objective.Type == OBJECTIVE_FINISH_5_ROLLERCOASTERS) + if (objective.Type == Scenario::ObjectiveType::finishFiveRollercoasters) ft.Add(objective.MinimumExcitement); else ft.Add(objective.Currency); diff --git a/src/openrct2-ui/interface/Objective.h b/src/openrct2-ui/interface/Objective.h index f22663d8ce..6ca381e666 100644 --- a/src/openrct2-ui/interface/Objective.h +++ b/src/openrct2-ui/interface/Objective.h @@ -13,11 +13,15 @@ #include class Formatter; -struct Objective; + +namespace OpenRCT2::Scenario +{ + struct Objective; +} namespace OpenRCT2::Ui { - void formatObjective(Formatter& ft, Objective objective); + void formatObjective(Formatter& ft, const Scenario::Objective& objective); extern const StringId kObjectiveNames[12]; } // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/scripting/ScTitleSequence.hpp b/src/openrct2-ui/scripting/ScTitleSequence.hpp index d9782420e6..9bc5982238 100644 --- a/src/openrct2-ui/scripting/ScTitleSequence.hpp +++ b/src/openrct2-ui/scripting/ScTitleSequence.hpp @@ -20,6 +20,7 @@ #include #include #include + #include #include #include #include diff --git a/src/openrct2-ui/windows/EditorBottomToolbar.cpp b/src/openrct2-ui/windows/EditorBottomToolbar.cpp index 702c7f2576..232f9e4674 100644 --- a/src/openrct2-ui/windows/EditorBottomToolbar.cpp +++ b/src/openrct2-ui/windows/EditorBottomToolbar.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/src/openrct2-ui/windows/EditorScenarioOptions.cpp b/src/openrct2-ui/windows/EditorScenarioOptions.cpp index f1c58af133..f4c7f7babc 100644 --- a/src/openrct2-ui/windows/EditorScenarioOptions.cpp +++ b/src/openrct2-ui/windows/EditorScenarioOptions.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -680,7 +681,7 @@ namespace OpenRCT2::Ui::Windows * * rct2: 0x0067201D */ - void SetObjective(int32_t objective) + void SetObjective(Scenario::ObjectiveType objective) { auto& gameState = getGameState(); auto& scenarioOptions = gameState.scenarioOptions; @@ -691,37 +692,39 @@ namespace OpenRCT2::Ui::Windows // Set default objective arguments switch (objective) { - case OBJECTIVE_NONE: - case OBJECTIVE_HAVE_FUN: - case OBJECTIVE_BUILD_THE_BEST: - case OBJECTIVE_10_ROLLERCOASTERS: + case Scenario::ObjectiveType::none: + case Scenario::ObjectiveType::haveFun: + case Scenario::ObjectiveType::buildTheBest: + case Scenario::ObjectiveType::tenRollercoasters: break; - case OBJECTIVE_GUESTS_BY: + case Scenario::ObjectiveType::guestsBy: scenarioOptions.objective.Year = 3; scenarioOptions.objective.NumGuests = 1500; break; - case OBJECTIVE_PARK_VALUE_BY: + case Scenario::ObjectiveType::parkValueBy: scenarioOptions.objective.Year = 3; scenarioOptions.objective.Currency = 50000.00_GBP; break; - case OBJECTIVE_GUESTS_AND_RATING: + case Scenario::ObjectiveType::guestsAndRating: scenarioOptions.objective.NumGuests = 2000; break; - case OBJECTIVE_MONTHLY_RIDE_INCOME: + case Scenario::ObjectiveType::monthlyRideIncome: scenarioOptions.objective.Currency = 10000.00_GBP; break; - case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + case Scenario::ObjectiveType::tenRollercoastersLength: scenarioOptions.objective.MinimumLength = 1200; break; - case OBJECTIVE_FINISH_5_ROLLERCOASTERS: + case Scenario::ObjectiveType::finishFiveRollercoasters: scenarioOptions.objective.MinimumExcitement = RideRating::make(6, 70); break; - case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE: + case Scenario::ObjectiveType::repayLoanAndParkValue: scenarioOptions.objective.Currency = 50000.00_GBP; break; - case OBJECTIVE_MONTHLY_FOOD_INCOME: + case Scenario::ObjectiveType::monthlyFoodIncome: scenarioOptions.objective.Currency = 1000.00_GBP; break; + default: + break; } } @@ -730,18 +733,20 @@ namespace OpenRCT2::Ui::Windows const auto& gameState = getGameState(); const auto& scenarioOptions = gameState.scenarioOptions; - int32_t numItems = 0, objectiveType; - - for (auto i = 0; i < OBJECTIVE_COUNT; i++) + int32_t numItems = 0; + for (auto i = 0; i < EnumValue(Scenario::ObjectiveType::count); i++) { - if (i == OBJECTIVE_NONE || i == OBJECTIVE_BUILD_THE_BEST) + auto obj = Scenario::ObjectiveType(i); + if (obj == Scenario::ObjectiveType::none || obj == Scenario::ObjectiveType::buildTheBest) continue; const bool objectiveAllowedByMoneyUsage = !(gameState.park.flags & PARK_FLAGS_NO_MONEY) - || !ObjectiveNeedsMoney(i); + || !Scenario::ObjectiveNeedsMoney(obj); + // This objective can only work if the player can ask money for rides. - const bool objectiveAllowedByPaymentSettings = (i != OBJECTIVE_MONTHLY_RIDE_INCOME) + const bool objectiveAllowedByPaymentSettings = (obj != Scenario::ObjectiveType::monthlyRideIncome) || Park::RidePricesUnlocked(); + if (objectiveAllowedByMoneyUsage && objectiveAllowedByPaymentSettings) { gDropdownItems[numItems].format = STR_DROPDOWN_MENU_LABEL; @@ -755,7 +760,7 @@ namespace OpenRCT2::Ui::Windows { windowPos.x + dropdownWidget->left, windowPos.y + dropdownWidget->top }, dropdownWidget->height() + 1, colours[1], 0, Dropdown::Flag::StayOpen, numItems, dropdownWidget->width() - 3); - objectiveType = scenarioOptions.objective.Type; + auto objectiveType = EnumValue(scenarioOptions.objective.Type); for (int32_t j = 0; j < numItems; j++) { if (gDropdownItems[j].args - STR_OBJECTIVE_DROPDOWN_NONE == objectiveType) @@ -789,9 +794,9 @@ namespace OpenRCT2::Ui::Windows switch (scenarioOptions.objective.Type) { - case OBJECTIVE_PARK_VALUE_BY: - case OBJECTIVE_MONTHLY_RIDE_INCOME: - case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE: + case Scenario::ObjectiveType::parkValueBy: + case Scenario::ObjectiveType::monthlyRideIncome: + case Scenario::ObjectiveType::repayLoanAndParkValue: if (scenarioOptions.objective.Currency >= kObjectiveCurrencyLoanAndValueMax) { ContextShowError(STR_CANT_INCREASE_FURTHER, kStringIdNone, {}); @@ -802,7 +807,7 @@ namespace OpenRCT2::Ui::Windows Invalidate(); } break; - case OBJECTIVE_MONTHLY_FOOD_INCOME: + case Scenario::ObjectiveType::monthlyFoodIncome: if (scenarioOptions.objective.Currency >= kObjectiveCurrencyFoodMax) { ContextShowError(STR_CANT_INCREASE_FURTHER, kStringIdNone, {}); @@ -813,7 +818,7 @@ namespace OpenRCT2::Ui::Windows Invalidate(); } break; - case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + case Scenario::ObjectiveType::tenRollercoastersLength: if (scenarioOptions.objective.MinimumLength >= kObjectiveLengthMax) { ContextShowError(STR_CANT_INCREASE_FURTHER, kStringIdNone, {}); @@ -824,7 +829,7 @@ namespace OpenRCT2::Ui::Windows Invalidate(); } break; - case OBJECTIVE_FINISH_5_ROLLERCOASTERS: + case Scenario::ObjectiveType::finishFiveRollercoasters: if (scenarioOptions.objective.MinimumExcitement >= kObjectiveExcitementMax) { ContextShowError(STR_CANT_INCREASE_FURTHER, kStringIdNone, {}); @@ -856,9 +861,9 @@ namespace OpenRCT2::Ui::Windows switch (scenarioOptions.objective.Type) { - case OBJECTIVE_PARK_VALUE_BY: - case OBJECTIVE_MONTHLY_RIDE_INCOME: - case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE: + case Scenario::ObjectiveType::parkValueBy: + case Scenario::ObjectiveType::monthlyRideIncome: + case Scenario::ObjectiveType::repayLoanAndParkValue: if (scenarioOptions.objective.Currency <= kObjectiveCurrencyLoanAndValueMin) { ContextShowError(STR_CANT_REDUCE_FURTHER, kStringIdNone, {}); @@ -869,7 +874,7 @@ namespace OpenRCT2::Ui::Windows Invalidate(); } break; - case OBJECTIVE_MONTHLY_FOOD_INCOME: + case Scenario::ObjectiveType::monthlyFoodIncome: if (scenarioOptions.objective.Currency <= kObjectiveCurrencyFoodMin) { ContextShowError(STR_CANT_REDUCE_FURTHER, kStringIdNone, {}); @@ -880,7 +885,7 @@ namespace OpenRCT2::Ui::Windows Invalidate(); } break; - case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + case Scenario::ObjectiveType::tenRollercoastersLength: if (scenarioOptions.objective.MinimumLength <= kObjectiveLengthMin) { ContextShowError(STR_CANT_REDUCE_FURTHER, kStringIdNone, {}); @@ -891,7 +896,7 @@ namespace OpenRCT2::Ui::Windows Invalidate(); } break; - case OBJECTIVE_FINISH_5_ROLLERCOASTERS: + case Scenario::ObjectiveType::finishFiveRollercoasters: if (scenarioOptions.objective.MinimumExcitement <= kObjectiveExcitementMin) { ContextShowError(STR_CANT_REDUCE_FURTHER, kStringIdNone, {}); @@ -1007,7 +1012,6 @@ namespace OpenRCT2::Ui::Windows void ObjectiveOnDropdown(WidgetIndex widgetIndex, int32_t dropdownIndex) { auto& gameState = getGameState(); - uint8_t newObjectiveType; if (dropdownIndex == -1) return; @@ -1016,7 +1020,8 @@ namespace OpenRCT2::Ui::Windows { case WIDX_OBJECTIVE_DROPDOWN: // TODO: Don't rely on string ID order - newObjectiveType = static_cast(gDropdownItems[dropdownIndex].args - STR_OBJECTIVE_DROPDOWN_NONE); + auto newObjectiveType = static_cast( + gDropdownItems[dropdownIndex].args - STR_OBJECTIVE_DROPDOWN_NONE); if (gameState.scenarioOptions.objective.Type != newObjectiveType) SetObjective(newObjectiveType); break; @@ -1029,24 +1034,24 @@ namespace OpenRCT2::Ui::Windows */ void ObjectiveOnUpdate() { - uint8_t objectiveType; - frame_no++; OnPrepareDraw(); InvalidateWidget(WIDX_TAB_1); - objectiveType = getGameState().scenarioOptions.objective.Type; + auto objectiveType = getGameState().scenarioOptions.objective.Type; // Check if objective is allowed by money and pay-per-ride settings. const bool objectiveAllowedByMoneyUsage = !(getGameState().park.flags & PARK_FLAGS_NO_MONEY) || !ObjectiveNeedsMoney(objectiveType); + // This objective can only work if the player can ask money for rides. - const bool objectiveAllowedByPaymentSettings = (objectiveType != OBJECTIVE_MONTHLY_RIDE_INCOME) + const bool objectiveAllowedByPaymentSettings = (objectiveType != Scenario::ObjectiveType::monthlyRideIncome) || Park::RidePricesUnlocked(); + if (!objectiveAllowedByMoneyUsage || !objectiveAllowedByPaymentSettings) { // Reset objective - SetObjective(OBJECTIVE_GUESTS_AND_RATING); + SetObjective(Scenario::ObjectiveType::guestsAndRating); } } @@ -1062,8 +1067,8 @@ namespace OpenRCT2::Ui::Windows switch (gameState.scenarioOptions.objective.Type) { - case OBJECTIVE_GUESTS_BY: - case OBJECTIVE_PARK_VALUE_BY: + case Scenario::ObjectiveType::guestsBy: + case Scenario::ObjectiveType::parkValueBy: widgets[WIDX_OBJECTIVE_ARG_1_LABEL].type = WidgetType::label; widgets[WIDX_OBJECTIVE_ARG_1].type = WidgetType::spinner; widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WidgetType::button; @@ -1073,12 +1078,12 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WidgetType::button; widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WidgetType::button; break; - case OBJECTIVE_GUESTS_AND_RATING: - case OBJECTIVE_MONTHLY_RIDE_INCOME: - case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: - case OBJECTIVE_FINISH_5_ROLLERCOASTERS: - case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE: - case OBJECTIVE_MONTHLY_FOOD_INCOME: + case Scenario::ObjectiveType::guestsAndRating: + case Scenario::ObjectiveType::monthlyRideIncome: + case Scenario::ObjectiveType::tenRollercoastersLength: + case Scenario::ObjectiveType::finishFiveRollercoasters: + case Scenario::ObjectiveType::repayLoanAndParkValue: + case Scenario::ObjectiveType::monthlyFoodIncome: widgets[WIDX_OBJECTIVE_ARG_1_LABEL].type = WidgetType::label; widgets[WIDX_OBJECTIVE_ARG_1].type = WidgetType::spinner; widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WidgetType::button; @@ -1106,21 +1111,21 @@ namespace OpenRCT2::Ui::Windows // Objective argument 1 label switch (gameState.scenarioOptions.objective.Type) { - case OBJECTIVE_GUESTS_BY: - case OBJECTIVE_GUESTS_AND_RATING: + case Scenario::ObjectiveType::guestsBy: + case Scenario::ObjectiveType::guestsAndRating: arg1StringId = STR_WINDOW_OBJECTIVE_GUEST_COUNT; break; - case OBJECTIVE_PARK_VALUE_BY: - case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE: + case Scenario::ObjectiveType::parkValueBy: + case Scenario::ObjectiveType::repayLoanAndParkValue: arg1StringId = STR_WINDOW_OBJECTIVE_PARK_VALUE; break; - case OBJECTIVE_MONTHLY_RIDE_INCOME: + case Scenario::ObjectiveType::monthlyRideIncome: arg1StringId = STR_WINDOW_OBJECTIVE_MONTHLY_INCOME; break; - case OBJECTIVE_MONTHLY_FOOD_INCOME: + case Scenario::ObjectiveType::monthlyFoodIncome: arg1StringId = STR_WINDOW_OBJECTIVE_MONTHLY_PROFIT; break; - case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + case Scenario::ObjectiveType::tenRollercoastersLength: arg1StringId = STR_WINDOW_OBJECTIVE_MINIMUM_LENGTH; break; default: @@ -1151,7 +1156,7 @@ namespace OpenRCT2::Ui::Windows // Objective value auto screenCoords = windowPos + ScreenCoordsXY{ widgets[WIDX_OBJECTIVE].left + 1, widgets[WIDX_OBJECTIVE].top }; auto ft = Formatter(); - ft.Add(ObjectiveDropdownOptionNames[scenarioOptions.objective.Type]); + ft.Add(ObjectiveDropdownOptionNames[EnumValue(scenarioOptions.objective.Type)]); DrawTextBasic(rt, screenCoords, STR_WINDOW_COLOUR_2_STRINGID, ft); if (widgets[WIDX_OBJECTIVE_ARG_1].type != WidgetType::empty) @@ -1165,23 +1170,23 @@ namespace OpenRCT2::Ui::Windows ft = Formatter(); switch (scenarioOptions.objective.Type) { - case OBJECTIVE_GUESTS_BY: - case OBJECTIVE_GUESTS_AND_RATING: + case Scenario::ObjectiveType::guestsBy: + case Scenario::ObjectiveType::guestsAndRating: stringId = STR_WINDOW_COLOUR_2_COMMA32; ft.Add(scenarioOptions.objective.NumGuests); break; - case OBJECTIVE_PARK_VALUE_BY: - case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE: - case OBJECTIVE_MONTHLY_RIDE_INCOME: - case OBJECTIVE_MONTHLY_FOOD_INCOME: + case Scenario::ObjectiveType::parkValueBy: + case Scenario::ObjectiveType::repayLoanAndParkValue: + case Scenario::ObjectiveType::monthlyRideIncome: + case Scenario::ObjectiveType::monthlyFoodIncome: stringId = STR_CURRENCY_FORMAT_LABEL; ft.Add(scenarioOptions.objective.Currency); break; - case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + case Scenario::ObjectiveType::tenRollercoastersLength: stringId = STR_WINDOW_COLOUR_2_LENGTH; ft.Add(scenarioOptions.objective.MinimumLength); break; - case OBJECTIVE_FINISH_5_ROLLERCOASTERS: + case Scenario::ObjectiveType::finishFiveRollercoasters: stringId = STR_WINDOW_COLOUR_2_COMMA2DP32; ft.Add(scenarioOptions.objective.MinimumExcitement); break; diff --git a/src/openrct2-ui/windows/Finances.cpp b/src/openrct2-ui/windows/Finances.cpp index 255e57c71c..bf9ad4fd36 100644 --- a/src/openrct2-ui/windows/Finances.cpp +++ b/src/openrct2-ui/windows/Finances.cpp @@ -636,7 +636,7 @@ namespace OpenRCT2::Ui::Windows DrawTextBasic(rt, windowPos + ScreenCoordsXY{ 8, titleBarBottom + 280 }, stringId, ft); // Objective related financial information - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_MONTHLY_FOOD_INCOME) + if (gameState.scenarioOptions.objective.Type == Scenario::ObjectiveType::monthlyFoodIncome) { auto lastMonthProfit = FinanceGetLastMonthShopProfit(); ft = Formatter(); diff --git a/src/openrct2-ui/windows/Park.cpp b/src/openrct2-ui/windows/Park.cpp index bd6caa44a0..ebc0f47d9a 100644 --- a/src/openrct2-ui/windows/Park.cpp +++ b/src/openrct2-ui/windows/Park.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -521,7 +522,7 @@ namespace OpenRCT2::Ui::Windows widgets[WIDX_OPEN_LIGHT].image = ImageId(openLightImage); // Only allow closing of park for guest / rating objective - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_GUESTS_AND_RATING) + if (gameState.scenarioOptions.objective.Type == Scenario::ObjectiveType::guestsAndRating) disabled_widgets |= (1uLL << WIDX_OPEN_OR_CLOSE) | (1uLL << WIDX_CLOSE_LIGHT) | (1uLL << WIDX_OPEN_LIGHT); else disabled_widgets &= ~((1uLL << WIDX_OPEN_OR_CLOSE) | (1uLL << WIDX_CLOSE_LIGHT) | (1uLL << WIDX_OPEN_LIGHT)); @@ -545,7 +546,7 @@ namespace OpenRCT2::Ui::Windows if (ThemeGetFlags() & UITHEME_FLAG_USE_LIGHTS_PARK) { widgets[WIDX_OPEN_OR_CLOSE].type = WidgetType::empty; - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_GUESTS_AND_RATING) + if (gameState.scenarioOptions.objective.Type == Scenario::ObjectiveType::guestsAndRating) { widgets[WIDX_CLOSE_LIGHT].type = WidgetType::flatBtn; widgets[WIDX_OPEN_LIGHT].type = WidgetType::flatBtn; @@ -1086,7 +1087,7 @@ namespace OpenRCT2::Ui::Windows formatObjective(ft, gameState.scenarioOptions.objective); screenCoords.y += DrawTextWrapped( - rt, screenCoords, 221, kObjectiveNames[gameState.scenarioOptions.objective.Type], ft); + rt, screenCoords, 221, kObjectiveNames[EnumValue(gameState.scenarioOptions.objective.Type)], ft); screenCoords.y += 5; // Objective outcome diff --git a/src/openrct2-ui/windows/ScenarioSelect.cpp b/src/openrct2-ui/windows/ScenarioSelect.cpp index d706f7e3ea..d1f2e6f6cf 100644 --- a/src/openrct2-ui/windows/ScenarioSelect.cpp +++ b/src/openrct2-ui/windows/ScenarioSelect.cpp @@ -392,13 +392,13 @@ namespace OpenRCT2::Ui::Windows screenPos.y += DrawTextWrapped(rt, screenPos, previewPaneWidth, STR_BLACK_STRING, ft) + 5; // Scenario objective - Objective objective = { .Type = scenario->ObjectiveType, - .Year = scenario->ObjectiveArg1, - .NumGuests = static_cast(scenario->ObjectiveArg3), - .Currency = scenario->ObjectiveArg2 }; + Scenario::Objective objective = { .Type = scenario->ObjectiveType, + .Year = scenario->ObjectiveArg1, + .NumGuests = static_cast(scenario->ObjectiveArg3), + .Currency = scenario->ObjectiveArg2 }; ft = Formatter(); - ft.Add(kObjectiveNames[scenario->ObjectiveType]); + ft.Add(kObjectiveNames[EnumValue(scenario->ObjectiveType)]); formatObjective(ft, objective); screenPos.y += DrawTextWrapped(rt, screenPos, previewPaneWidth, STR_OBJECTIVE, ft) + 5; diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index 23fb133900..80a6f5c2f7 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -60,6 +60,7 @@ #include "profiling/Profiling.h" #include "rct2/RCT2.h" #include "ride/TrackDesignRepository.h" +#include "scenario/Scenario.h" #include "scenario/ScenarioRepository.h" #include "scenes/game/GameScene.h" #include "scenes/intro/IntroScene.h" diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index 769180d0fa..b5fc2f57cb 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -38,6 +38,7 @@ #include "object/ObjectRepository.h" #include "peep/PeepAnimations.h" #include "rct1/RCT1.h" +#include "scenario/Scenario.h" #include "scripting/ScriptEngine.h" #include "ui/WindowManager.h" #include "windows/Intent.h" diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 1301efe5c7..df091bb3a8 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -57,6 +57,7 @@ #include "ride/TrackDesign.h" #include "ride/Vehicle.h" #include "sawyer_coding/SawyerCoding.h" +#include "scenario/Scenario.h" #include "scenes/title/TitleScene.h" #include "scripting/ScriptEngine.h" #include "ui/UiContext.h" diff --git a/src/openrct2/GameState.cpp b/src/openrct2/GameState.cpp index 43dbcb8e4e..fd13eb4a31 100644 --- a/src/openrct2/GameState.cpp +++ b/src/openrct2/GameState.cpp @@ -22,6 +22,7 @@ #include "platform/Platform.h" #include "profiling/Profiling.h" #include "ride/Vehicle.h" +#include "scenario/Scenario.h" #include "scenes/title/TitleScene.h" #include "scenes/title/TitleSequencePlayer.h" #include "scripting/ScriptEngine.h" diff --git a/src/openrct2/GameState.h b/src/openrct2/GameState.h index 8cb4c56255..ab19384aee 100644 --- a/src/openrct2/GameState.h +++ b/src/openrct2/GameState.h @@ -13,6 +13,7 @@ #include "Date.h" #include "Editor.h" #include "Limits.h" +#include "core/Random.hpp" #include "entity/EntityRegistry.h" #include "interface/ZoomLevel.h" #include "management/Finance.h" diff --git a/src/openrct2/ReplayManager.cpp b/src/openrct2/ReplayManager.cpp index 779c4cafcd..cf647dcb0d 100644 --- a/src/openrct2/ReplayManager.cpp +++ b/src/openrct2/ReplayManager.cpp @@ -37,6 +37,7 @@ #include "object/ObjectManager.h" #include "object/ObjectRepository.h" #include "park/ParkFile.h" +#include "scenario/Scenario.h" #include "world/Park.h" #include diff --git a/src/openrct2/actions/CheatSetAction.cpp b/src/openrct2/actions/CheatSetAction.cpp index 01bcebe969..9c2c1f6f0f 100644 --- a/src/openrct2/actions/CheatSetAction.cpp +++ b/src/openrct2/actions/CheatSetAction.cpp @@ -27,6 +27,8 @@ #include "../ride/Ride.h" #include "../ride/RideManager.hpp" #include "../ride/Vehicle.h" +#include "../scenario/Scenario.h" +#include "../scenario/ScenarioObjective.h" #include "../ui/WindowManager.h" #include "../util/Util.h" #include "../windows/Intent.h" @@ -234,7 +236,7 @@ GameActions::Result CheatSetAction::Execute() const ParkSetOpen(!Park::IsOpen(gameState.park)); break; case CheatType::HaveFun: - gameState.scenarioOptions.objective.Type = OBJECTIVE_HAVE_FUN; + gameState.scenarioOptions.objective.Type = Scenario::ObjectiveType::haveFun; break; case CheatType::SetForcedParkRating: Park::SetForcedRating(_param1); diff --git a/src/openrct2/actions/GameAction.cpp b/src/openrct2/actions/GameAction.cpp index 94245baaf8..6ac0b5355d 100644 --- a/src/openrct2/actions/GameAction.cpp +++ b/src/openrct2/actions/GameAction.cpp @@ -21,6 +21,7 @@ #include "../network/Network.h" #include "../platform/Platform.h" #include "../profiling/Profiling.h" +#include "../scenario/Scenario.h" #include "../scripting/Duktape.hpp" #include "../scripting/HookEngine.h" #include "../scripting/ScriptEngine.h" diff --git a/src/openrct2/actions/RideCreateAction.cpp b/src/openrct2/actions/RideCreateAction.cpp index 4490b7bc0f..283daaaaa2 100644 --- a/src/openrct2/actions/RideCreateAction.cpp +++ b/src/openrct2/actions/RideCreateAction.cpp @@ -226,7 +226,7 @@ GameActions::Result RideCreateAction::Execute() const ride->price[1] = GetShopItemDescriptor(rideEntry->shop_item[1]).DefaultPrice; } - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_BUILD_THE_BEST) + if (gameState.scenarioOptions.objective.Type == Scenario::ObjectiveType::buildTheBest) { ride->price[0] = 0; } diff --git a/src/openrct2/actions/ScenarioSetSettingAction.cpp b/src/openrct2/actions/ScenarioSetSettingAction.cpp index b2cd442cbd..6b697f3f2d 100644 --- a/src/openrct2/actions/ScenarioSetSettingAction.cpp +++ b/src/openrct2/actions/ScenarioSetSettingAction.cpp @@ -14,6 +14,7 @@ #include "../OpenRCT2.h" #include "../entity/Peep.h" #include "../management/Finance.h" +#include "../scenario/Scenario.h" #include "../ui/WindowManager.h" #include "../world/Park.h" diff --git a/src/openrct2/actions/StaffHireNewAction.cpp b/src/openrct2/actions/StaffHireNewAction.cpp index 67ff44829f..f5705124b4 100644 --- a/src/openrct2/actions/StaffHireNewAction.cpp +++ b/src/openrct2/actions/StaffHireNewAction.cpp @@ -23,6 +23,7 @@ #include "../object/ObjectManager.h" #include "../object/PeepAnimationsObject.h" #include "../ride/Ride.h" +#include "../scenario/Scenario.h" #include "../ui/WindowManager.h" #include "../world/Entrance.h" #include "../world/Park.h" diff --git a/src/openrct2/command_line/ConvertCommand.cpp b/src/openrct2/command_line/ConvertCommand.cpp index b690973a66..3decdf7860 100644 --- a/src/openrct2/command_line/ConvertCommand.cpp +++ b/src/openrct2/command_line/ConvertCommand.cpp @@ -16,8 +16,10 @@ #include "../config/Config.h" #include "../core/Console.hpp" #include "../core/Path.hpp" +#include "../core/String.hpp" #include "../object/ObjectManager.h" #include "../park/ParkFile.h" +#include "../scenario/Scenario.h" #include "../ui/WindowManager.h" #include "CommandLine.hpp" diff --git a/src/openrct2/core/Random.hpp b/src/openrct2/core/Random.hpp index 03b5ddb955..2d051b186e 100644 --- a/src/openrct2/core/Random.hpp +++ b/src/openrct2/core/Random.hpp @@ -200,3 +200,5 @@ namespace OpenRCT2::Random using State = Engine::state_type; } // namespace RCT2 } // namespace OpenRCT2::Random + +using random_engine_t = OpenRCT2::Random::RCT2::Engine; diff --git a/src/openrct2/entity/Duck.cpp b/src/openrct2/entity/Duck.cpp index 8a7ab9dd2f..0f82511d76 100644 --- a/src/openrct2/entity/Duck.cpp +++ b/src/openrct2/entity/Duck.cpp @@ -6,6 +6,7 @@ * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ + #include "Duck.h" #include "../Game.h" @@ -16,6 +17,7 @@ #include "../entity/EntityList.h" #include "../paint/Paint.h" #include "../profiling/Profiling.h" +#include "../scenario/Scenario.h" #include "../world/tile_element/SurfaceElement.h" #include "EntityRegistry.h" diff --git a/src/openrct2/entity/Fountain.cpp b/src/openrct2/entity/Fountain.cpp index febefdda48..6dc5ed9861 100644 --- a/src/openrct2/entity/Fountain.cpp +++ b/src/openrct2/entity/Fountain.cpp @@ -15,6 +15,7 @@ #include "../object/PathAdditionEntry.h" #include "../paint/Paint.h" #include "../profiling/Profiling.h" +#include "../scenario/Scenario.h" #include "../world/Footpath.h" #include "../world/Location.hpp" #include "../world/Map.h" diff --git a/src/openrct2/entity/Guest.cpp b/src/openrct2/entity/Guest.cpp index 873cc8cae9..b0393fa2b6 100644 --- a/src/openrct2/entity/Guest.cpp +++ b/src/openrct2/entity/Guest.cpp @@ -52,6 +52,7 @@ #include "../ride/Station.h" #include "../ride/Track.h" #include "../ride/Vehicle.h" +#include "../scenario/Scenario.h" #include "../scripting/HookEngine.h" #include "../scripting/ScriptEngine.h" #include "../ui/WindowManager.h" diff --git a/src/openrct2/entity/Peep.cpp b/src/openrct2/entity/Peep.cpp index f164c3d146..febdd5cd34 100644 --- a/src/openrct2/entity/Peep.cpp +++ b/src/openrct2/entity/Peep.cpp @@ -49,6 +49,7 @@ #include "../ride/ShopItem.h" #include "../ride/Station.h" #include "../ride/Track.h" +#include "../scenario/Scenario.h" #include "../ui/WindowManager.h" #include "../util/Util.h" #include "../windows/Intent.h" diff --git a/src/openrct2/entity/Staff.cpp b/src/openrct2/entity/Staff.cpp index b67aa7c921..e8efa8d192 100644 --- a/src/openrct2/entity/Staff.cpp +++ b/src/openrct2/entity/Staff.cpp @@ -39,6 +39,7 @@ #include "../ride/Station.h" #include "../ride/Track.h" #include "../ride/Vehicle.h" +#include "../scenario/Scenario.h" #include "../util/Util.h" #include "../windows/Intent.h" #include "../world/Entrance.h" diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index f23c1d52c0..ef10cf4c00 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -548,6 +548,7 @@ + @@ -1085,6 +1086,7 @@ + diff --git a/src/openrct2/management/Award.cpp b/src/openrct2/management/Award.cpp index f0fd89d061..bbe22297f9 100644 --- a/src/openrct2/management/Award.cpp +++ b/src/openrct2/management/Award.cpp @@ -17,6 +17,7 @@ #include "../ride/Ride.h" #include "../ride/RideData.h" #include "../ride/RideManager.hpp" +#include "../scenario/Scenario.h" #include "../ui/WindowManager.h" #include "../world/Park.h" #include "NewsItem.h" diff --git a/src/openrct2/management/Research.cpp b/src/openrct2/management/Research.cpp index 605dd7ae08..67ee65fa2e 100644 --- a/src/openrct2/management/Research.cpp +++ b/src/openrct2/management/Research.cpp @@ -33,6 +33,7 @@ #include "../ride/RideData.h" #include "../ride/RideEntry.h" #include "../ride/TrackData.h" +#include "../scenario/Scenario.h" #include "../ui/WindowManager.h" #include "../windows/Intent.h" #include "../world/Park.h" diff --git a/src/openrct2/network/NetworkBase.h b/src/openrct2/network/NetworkBase.h index a144b995ac..20c8c4c6d8 100644 --- a/src/openrct2/network/NetworkBase.h +++ b/src/openrct2/network/NetworkBase.h @@ -3,6 +3,7 @@ #include "../System.hpp" #include "../actions/GameAction.h" #include "../object/Object.h" +#include "../scenario/Scenario.h" #include "NetworkConnection.h" #include "NetworkGroup.h" #include "NetworkPlayer.h" diff --git a/src/openrct2/park/ParkFile.cpp b/src/openrct2/park/ParkFile.cpp index 5c8ccac126..cce30bc736 100644 --- a/src/openrct2/park/ParkFile.cpp +++ b/src/openrct2/park/ParkFile.cpp @@ -49,6 +49,7 @@ #include "../ride/RideManager.hpp" #include "../ride/ShopItem.h" #include "../ride/Vehicle.h" +#include "../scenario/Scenario.h" #include "../scenario/ScenarioRepository.h" #include "../scripting/ScriptEngine.h" #include "../ui/WindowManager.h" @@ -233,7 +234,7 @@ namespace OpenRCT2 entry.Details = scenarioDetails; // wrong order is intentional here due to ReadWriteScenarioChunk writing guests first - entry.ObjectiveType = cs.read(); + entry.ObjectiveType = cs.read(); entry.ObjectiveArg1 = cs.read(); entry.ObjectiveArg3 = cs.read(); entry.ObjectiveArg2 = cs.read(); diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 30cf341377..74f34af04d 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -18,6 +18,7 @@ #include "../ride/RideData.h" #include "../ride/Station.h" #include "../ride/Track.h" +#include "../scenario/Scenario.h" #include "../world/Entrance.h" #include "../world/Footpath.h" #include "../world/tile_element/BannerElement.h" diff --git a/src/openrct2/rct1/RCT1.h b/src/openrct2/rct1/RCT1.h index 6912851dac..f747ac66a4 100644 --- a/src/openrct2/rct1/RCT1.h +++ b/src/openrct2/rct1/RCT1.h @@ -18,6 +18,11 @@ enum class VehicleColourSettings : uint8_t; +namespace OpenRCT2::Scenario +{ + enum class ObjectiveType : uint8_t; +} + namespace OpenRCT2::RCT1 { constexpr uint8_t RCT1ResearchFlagsSeparator = 0xFF; @@ -800,7 +805,7 @@ namespace OpenRCT2::RCT1 money16 GuestInitialCash; uint8_t GuestInitialHunger; uint8_t GuestInitialThirst; - uint8_t ScenarioObjectiveType; + Scenario::ObjectiveType ScenarioObjectiveType; uint8_t ScenarioObjectiveYears; uint16_t Unk199552; money32 ScenarioObjectiveCurrency; diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 2cf11a3cf2..7ce75afe87 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -63,6 +63,8 @@ #include "../ride/TrainManager.h" #include "../ride/Vehicle.h" #include "../sawyer_coding/SawyerCoding.h" +#include "../scenario/Scenario.h" +#include "../scenario/ScenarioObjective.h" #include "../scenario/ScenarioRepository.h" #include "../scenario/ScenarioSources.h" #include "../world/Climate.h" @@ -245,13 +247,13 @@ namespace OpenRCT2::RCT1 dst->ObjectiveType = _s4.ScenarioObjectiveType; dst->ObjectiveArg1 = _s4.ScenarioObjectiveYears; // RCT1 used another way of calculating park value. - if (_s4.ScenarioObjectiveType == OBJECTIVE_PARK_VALUE_BY) + if (_s4.ScenarioObjectiveType == Scenario::ObjectiveType::parkValueBy) dst->ObjectiveArg2 = CorrectRCT1ParkValue(_s4.ScenarioObjectiveCurrency); else dst->ObjectiveArg2 = _s4.ScenarioObjectiveCurrency; dst->ObjectiveArg3 = _s4.ScenarioObjectiveNumGuests; // This does not seem to be saved in the objective arguments, so look up the ID from the available rides instead. - if (_s4.ScenarioObjectiveType == OBJECTIVE_BUILD_THE_BEST) + if (_s4.ScenarioObjectiveType == Scenario::ObjectiveType::buildTheBest) { dst->ObjectiveArg3 = GetBuildTheBestRideId(); } @@ -2465,13 +2467,13 @@ namespace OpenRCT2::RCT1 // 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.ScenarioObjectiveType == OBJECTIVE_PARK_VALUE_BY) + if (_s4.ScenarioObjectiveType == Scenario::ObjectiveType::parkValueBy) gameState.scenarioOptions.objective.Currency = CorrectRCT1ParkValue(_s4.ScenarioObjectiveCurrency); else gameState.scenarioOptions.objective.Currency = ToMoney64(_s4.ScenarioObjectiveCurrency); // This does not seem to be saved in the objective arguments, so look up the ID from the available rides instead. - if (_s4.ScenarioObjectiveType == OBJECTIVE_BUILD_THE_BEST) + if (_s4.ScenarioObjectiveType == Scenario::ObjectiveType::buildTheBest) gameState.scenarioOptions.objective.RideId = GetBuildTheBestRideId(); } diff --git a/src/openrct2/rct2/RCT2.h b/src/openrct2/rct2/RCT2.h index d72798d88e..6a8d976215 100644 --- a/src/openrct2/rct2/RCT2.h +++ b/src/openrct2/rct2/RCT2.h @@ -29,6 +29,12 @@ namespace OpenRCT2 class ObjectList; } +namespace OpenRCT2::Scenario +{ + enum class Category : uint8_t; + enum class ObjectiveType : uint8_t; +} // namespace OpenRCT2::Scenario + namespace OpenRCT2::RCT2 { constexpr StringId kRCT2RideStringStart = 2; @@ -394,7 +400,7 @@ namespace OpenRCT2::RCT2 char Path[256]; uint8_t Category; uint8_t Pad0101[0x1F]; - int8_t ObjectiveType; + Scenario::ObjectiveType ObjectiveType; int8_t ObjectiveArg1; int32_t objectiveArg2; uint16_t objectiveArg3; @@ -762,11 +768,11 @@ namespace OpenRCT2::RCT2 struct S6Info { ::EditorStep EditorStep; - ScenarioCategory Category; // 0x01 - uint8_t ObjectiveType; // 0x02 - uint8_t ObjectiveArg1; // 0x03 - int32_t ObjectiveArg2; // 0x04 - uint16_t ObjectiveArg3; // 0x08 + Scenario::Category Category; // 0x01 + Scenario::ObjectiveType ObjectiveType; // 0x02 + uint8_t ObjectiveArg1; // 0x03 + int32_t ObjectiveArg2; // 0x04 + uint16_t ObjectiveArg3; // 0x08 uint8_t Pad00A[0x3E]; char Name[64]; // 0x48 char Details[256]; // 0x88 @@ -883,7 +889,7 @@ namespace OpenRCT2::RCT2 money16 GuestInitialCash; uint8_t GuestInitialHunger; uint8_t GuestInitialThirst; - uint8_t ObjectiveType; + Scenario::ObjectiveType ObjectiveType; uint8_t ObjectiveYear; uint8_t Pad013580FA[2]; money32 ObjectiveCurrency; diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 75cd155ba5..d9b4169139 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -68,6 +68,7 @@ #include "../ride/Vehicle.h" #include "../sawyer_coding/SawyerChunkReader.h" #include "../sawyer_coding/SawyerCoding.h" +#include "../scenario/Scenario.h" #include "../scenario/ScenarioRepository.h" #include "../scenario/ScenarioSources.h" #include "../world/Climate.h" @@ -474,7 +475,7 @@ namespace OpenRCT2::RCT2 gameState.scenarioOptions.objective.Currency = _s6.ObjectiveCurrency; // 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 (gameState.scenarioOptions.objective.Type == OBJECTIVE_BUILD_THE_BEST) + if (gameState.scenarioOptions.objective.Type == Scenario::ObjectiveType::buildTheBest) gameState.scenarioOptions.objective.RideId = _s6.ObjectiveGuests - kRCT2RideStringStart; else gameState.scenarioOptions.objective.NumGuests = _s6.ObjectiveGuests; diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 44000088f2..fc0f974dc2 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -47,6 +47,7 @@ #include "../object/StationObject.h" #include "../profiling/Profiling.h" #include "../rct1/RCT1.h" +#include "../scenario/Scenario.h" #include "../ui/WindowManager.h" #include "../util/Util.h" #include "../windows/Intent.h" diff --git a/src/openrct2/ride/Station.cpp b/src/openrct2/ride/Station.cpp index 4bbf31785e..8a12faec2d 100644 --- a/src/openrct2/ride/Station.cpp +++ b/src/openrct2/ride/Station.cpp @@ -12,6 +12,7 @@ #include "../Game.h" #include "../GameState.h" #include "../entity/Guest.h" +#include "../scenario/Scenario.h" #include "../world/Location.hpp" #include "../world/tile_element/TileElement.h" #include "../world/tile_element/TrackElement.h" diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index a50785bf8e..3dc273d055 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -38,6 +38,7 @@ #include "../platform/Platform.h" #include "../profiling/Profiling.h" #include "../rct12/RCT12.h" +#include "../scenario/Scenario.h" #include "../scripting/HookEngine.h" #include "../scripting/ScriptEngine.h" #include "../ui/WindowManager.h" diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 0daafc0baa..1b85efb38f 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -7,6 +7,8 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "Scenario.h" + #include "../Cheats.h" #include "../Context.h" #include "../Date.h" @@ -65,6 +67,7 @@ #include using namespace OpenRCT2; +using namespace OpenRCT2::Scenario; const StringId kScenarioCategoryStringIds[EnumValue(ScenarioCategory::count)] = { STR_BEGINNER_PARKS, STR_CHALLENGING_PARKS, STR_EXPERT_PARKS, STR_REAL_PARKS, STR_OTHER_PARKS, @@ -84,7 +87,7 @@ void ScenarioBegin(GameState_t& gameState) GameLoadInit(); ScenarioReset(gameState); - if (gameState.scenarioOptions.objective.Type != OBJECTIVE_NONE && !gLoadKeepWindowsOpen) + if (gameState.scenarioOptions.objective.Type != ObjectiveType::none && !gLoadKeepWindowsOpen) ContextOpenWindowView(WV_PARK_OBJECTIVE); gScreenAge = 0; @@ -287,11 +290,11 @@ static void ScenarioDayUpdate(GameState_t& gameState) PeepUpdateDaysInQueue(); switch (gameState.scenarioOptions.objective.Type) { - case OBJECTIVE_10_ROLLERCOASTERS: - case OBJECTIVE_GUESTS_AND_RATING: - case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: - case OBJECTIVE_FINISH_5_ROLLERCOASTERS: - case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE: + case ObjectiveType::tenRollercoasters: + case ObjectiveType::guestsAndRating: + case ObjectiveType::tenRollercoastersLength: + case ObjectiveType::finishFiveRollercoasters: + case ObjectiveType::repayLoanAndParkValue: ScenarioCheckObjective(gameState); break; default: @@ -526,7 +529,7 @@ uint32_t ScenarioRandMax(uint32_t max) */ static ResultWithMessage ScenarioPrepareRidesForSave(GameState_t& gameState) { - int32_t isFiveCoasterObjective = gameState.scenarioOptions.objective.Type == OBJECTIVE_FINISH_5_ROLLERCOASTERS; + bool isFiveCoasterObjective = gameState.scenarioOptions.objective.Type == ObjectiveType::finishFiveRollercoasters; uint8_t rcs = 0; for (auto& ride : GetRideManager()) @@ -592,7 +595,7 @@ ResultWithMessage ScenarioPrepareForSave(GameState_t& gameState) return { false, prepareRidesResult.Message }; } - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_GUESTS_AND_RATING) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::guestsAndRating) gameState.park.flags |= PARK_FLAGS_PARK_OPEN; ScenarioReset(gameState); @@ -600,245 +603,6 @@ ResultWithMessage ScenarioPrepareForSave(GameState_t& gameState) return { true }; } -ObjectiveStatus Objective::CheckGuestsBy() const -{ - auto parkRating = getGameState().park.rating; - int32_t currentMonthYear = GetDate().GetMonthsElapsed(); - - if (currentMonthYear == MONTH_COUNT * Year || AllowEarlyCompletion()) - { - if (parkRating >= 600 && getGameState().park.numGuestsInPark >= NumGuests) - { - return ObjectiveStatus::Success; - } - - if (currentMonthYear == MONTH_COUNT * Year) - { - return ObjectiveStatus::Failure; - } - } - - return ObjectiveStatus::Undecided; -} - -ObjectiveStatus Objective::CheckParkValueBy() const -{ - int32_t currentMonthYear = GetDate().GetMonthsElapsed(); - money64 objectiveParkValue = Currency; - money64 parkValue = getGameState().park.value; - - if (currentMonthYear == MONTH_COUNT * Year || AllowEarlyCompletion()) - { - if (parkValue >= objectiveParkValue) - { - return ObjectiveStatus::Success; - } - - if (currentMonthYear == MONTH_COUNT * Year) - { - return ObjectiveStatus::Failure; - } - } - - return ObjectiveStatus::Undecided; -} - -/** - * Checks if there are 10 rollercoasters of different subtype with - * excitement >= 600 . - * rct2: - **/ -ObjectiveStatus Objective::Check10RollerCoasters() const -{ - auto rcs = 0; - BitSet type_already_counted; - for (const auto& ride : GetRideManager()) - { - if (ride.status == RideStatus::open && ride.ratings.excitement >= RideRating::make(6, 00) - && ride.subtype != kObjectEntryIndexNull) - { - auto rideEntry = ride.getRideEntry(); - if (rideEntry != nullptr) - { - if (RideEntryHasCategory(*rideEntry, RideCategory::rollerCoaster) && !type_already_counted[ride.subtype]) - { - type_already_counted[ride.subtype] = true; - rcs++; - } - } - } - } - if (rcs >= 10) - { - return ObjectiveStatus::Success; - } - - return ObjectiveStatus::Undecided; -} - -/** - * - * rct2: 0x0066A13C - */ -ObjectiveStatus Objective::CheckGuestsAndRating() const -{ - auto& gameState = getGameState(); - if (gameState.park.rating < 700 && GetDate().GetMonthsElapsed() >= 1) - { - gameState.scenarioParkRatingWarningDays++; - if (gameState.scenarioParkRatingWarningDays == 1) - { - if (Config::Get().notifications.ParkRatingWarnings) - { - News::AddItemToQueue(News::ItemType::graph, STR_PARK_RATING_WARNING_4_WEEKS_REMAINING, 0, {}); - } - } - else if (gameState.scenarioParkRatingWarningDays == 8) - { - if (Config::Get().notifications.ParkRatingWarnings) - { - News::AddItemToQueue(News::ItemType::graph, STR_PARK_RATING_WARNING_3_WEEKS_REMAINING, 0, {}); - } - } - else if (gameState.scenarioParkRatingWarningDays == 15) - { - if (Config::Get().notifications.ParkRatingWarnings) - { - News::AddItemToQueue(News::ItemType::graph, STR_PARK_RATING_WARNING_2_WEEKS_REMAINING, 0, {}); - } - } - else if (gameState.scenarioParkRatingWarningDays == 22) - { - if (Config::Get().notifications.ParkRatingWarnings) - { - News::AddItemToQueue(News::ItemType::graph, STR_PARK_RATING_WARNING_1_WEEK_REMAINING, 0, {}); - } - } - else if (gameState.scenarioParkRatingWarningDays == 29) - { - News::AddItemToQueue(News::ItemType::graph, STR_PARK_HAS_BEEN_CLOSED_DOWN, 0, {}); - gameState.park.flags &= ~PARK_FLAGS_PARK_OPEN; - gameState.scenarioOptions.guestInitialHappiness = 50; - return ObjectiveStatus::Failure; - } - } - else if (gameState.scenarioCompletedCompanyValue != kCompanyValueOnFailedObjective) - { - gameState.scenarioParkRatingWarningDays = 0; - } - - if (gameState.park.rating >= 700) - if (gameState.park.numGuestsInPark >= NumGuests) - return ObjectiveStatus::Success; - - return ObjectiveStatus::Undecided; -} - -ObjectiveStatus Objective::CheckMonthlyRideIncome() const -{ - money64 lastMonthRideIncome = getGameState().park.expenditureTable[1][EnumValue(ExpenditureType::parkRideTickets)]; - if (lastMonthRideIncome >= Currency) - { - return ObjectiveStatus::Success; - } - - return ObjectiveStatus::Undecided; -} - -/** - * Checks if there are 10 rollercoasters of different subtype with - * excitement > 700 and a minimum length; - * rct2: 0x0066A6B5 - */ -ObjectiveStatus Objective::Check10RollerCoastersLength() const -{ - BitSet type_already_counted; - auto rcs = 0; - for (const auto& ride : GetRideManager()) - { - if (ride.status == RideStatus::open && ride.ratings.excitement >= RideRating::make(7, 00) - && ride.subtype != kObjectEntryIndexNull) - { - auto rideEntry = ride.getRideEntry(); - if (rideEntry != nullptr) - { - if (RideEntryHasCategory(*rideEntry, RideCategory::rollerCoaster) && !type_already_counted[ride.subtype]) - { - if (ToHumanReadableRideLength(ride.getTotalLength()) >= MinimumLength) - { - type_already_counted[ride.subtype] = true; - rcs++; - } - } - } - } - } - if (rcs >= 10) - { - return ObjectiveStatus::Success; - } - - return ObjectiveStatus::Undecided; -} - -ObjectiveStatus Objective::CheckFinish5RollerCoasters() const -{ - // 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 != RideStatus::closed && ride.ratings.excitement >= MinimumExcitement) - { - auto rideEntry = ride.getRideEntry(); - if (rideEntry != nullptr) - { - if ((ride.lifecycleFlags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) - && RideEntryHasCategory(*rideEntry, RideCategory::rollerCoaster)) - { - rcs++; - } - } - } - } - if (rcs >= 5) - { - return ObjectiveStatus::Success; - } - - return ObjectiveStatus::Undecided; -} - -ObjectiveStatus Objective::CheckRepayLoanAndParkValue() const -{ - const auto& gameState = getGameState(); - money64 parkValue = gameState.park.value; - money64 currentLoan = gameState.park.bankLoan; - - if (currentLoan <= 0 && parkValue >= Currency) - { - return ObjectiveStatus::Success; - } - - return ObjectiveStatus::Undecided; -} - -ObjectiveStatus Objective::CheckMonthlyFoodIncome() const -{ - const auto* lastMonthExpenditure = getGameState().park.expenditureTable[1]; - auto lastMonthProfit = lastMonthExpenditure[EnumValue(ExpenditureType::shopSales)] - + lastMonthExpenditure[EnumValue(ExpenditureType::shopStock)] - + lastMonthExpenditure[EnumValue(ExpenditureType::foodDrinkSales)] - + lastMonthExpenditure[EnumValue(ExpenditureType::foodDrinkStock)]; - - if (lastMonthProfit >= Currency) - { - return ObjectiveStatus::Success; - } - - return ObjectiveStatus::Undecided; -} - /* * Returns the AllowEarlyCompletion-Option to be used * depending on the Current Network-Mode. @@ -868,53 +632,3 @@ static void ScenarioCheckObjective(GameState_t& gameState) ScenarioFailure(gameState); } } - -/** - * Checks the win/lose conditions of the current objective. - * rct2: 0x0066A4B2 - */ -ObjectiveStatus Objective::Check(GameState_t& gameState) const -{ - if (gameState.scenarioCompletedCompanyValue != kMoney64Undefined) - { - return ObjectiveStatus::Undecided; - } - - switch (Type) - { - case OBJECTIVE_GUESTS_BY: - return CheckGuestsBy(); - case OBJECTIVE_PARK_VALUE_BY: - return CheckParkValueBy(); - case OBJECTIVE_10_ROLLERCOASTERS: - return Check10RollerCoasters(); - case OBJECTIVE_GUESTS_AND_RATING: - return CheckGuestsAndRating(); - case OBJECTIVE_MONTHLY_RIDE_INCOME: - return CheckMonthlyRideIncome(); - case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: - return Check10RollerCoastersLength(); - case OBJECTIVE_FINISH_5_ROLLERCOASTERS: - return CheckFinish5RollerCoasters(); - case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE: - return CheckRepayLoanAndParkValue(); - case OBJECTIVE_MONTHLY_FOOD_INCOME: - return CheckMonthlyFoodIncome(); - } - - return ObjectiveStatus::Undecided; -} - -bool ObjectiveNeedsMoney(const uint8_t objective) -{ - switch (objective) - { - case OBJECTIVE_PARK_VALUE_BY: - case OBJECTIVE_MONTHLY_RIDE_INCOME: - case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE: - case OBJECTIVE_MONTHLY_FOOD_INCOME: - return true; - } - - return false; -} diff --git a/src/openrct2/scenario/Scenario.h b/src/openrct2/scenario/Scenario.h index 46ab33276b..66fee757ed 100644 --- a/src/openrct2/scenario/Scenario.h +++ b/src/openrct2/scenario/Scenario.h @@ -18,8 +18,6 @@ struct ResultWithMessage; -using random_engine_t = OpenRCT2::Random::RCT2::Engine; - namespace OpenRCT2 { struct GameState_t; @@ -57,76 +55,6 @@ enum class ScenarioCategory : uint8_t count, }; -enum -{ - OBJECTIVE_NONE, - OBJECTIVE_GUESTS_BY, - OBJECTIVE_PARK_VALUE_BY, - OBJECTIVE_HAVE_FUN, - OBJECTIVE_BUILD_THE_BEST, - OBJECTIVE_10_ROLLERCOASTERS, - OBJECTIVE_GUESTS_AND_RATING, - OBJECTIVE_MONTHLY_RIDE_INCOME, - OBJECTIVE_10_ROLLERCOASTERS_LENGTH, - OBJECTIVE_FINISH_5_ROLLERCOASTERS, - OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE, - OBJECTIVE_MONTHLY_FOOD_INCOME, - - 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; - StringId RideId; - uint16_t MinimumLength; // For the "Build 10 coasters of minimum length" objective. - }; - union - { - money64 Currency; - OpenRCT2::RideRating_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(OpenRCT2::GameState_t& gameState) 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 { AUTOSAVE_EVERY_MINUTE, diff --git a/src/openrct2/scenario/ScenarioObjective.cpp b/src/openrct2/scenario/ScenarioObjective.cpp new file mode 100644 index 0000000000..004b278c42 --- /dev/null +++ b/src/openrct2/scenario/ScenarioObjective.cpp @@ -0,0 +1,309 @@ +/***************************************************************************** + * Copyright (c) 2014-2025 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ScenarioObjective.h" + +#include "../GameState.h" +#include "../config/Config.h" +#include "../core/UnitConversion.h" +#include "../object/ObjectLimits.h" +#include "../ride/RideManager.hpp" +#include "Scenario.h" + +namespace OpenRCT2::Scenario +{ + ObjectiveStatus Objective::CheckGuestsBy() const + { + auto parkRating = getGameState().park.rating; + int32_t currentMonthYear = GetDate().GetMonthsElapsed(); + + if (currentMonthYear == MONTH_COUNT * Year || AllowEarlyCompletion()) + { + if (parkRating >= 600 && getGameState().park.numGuestsInPark >= NumGuests) + { + return ObjectiveStatus::Success; + } + + if (currentMonthYear == MONTH_COUNT * Year) + { + return ObjectiveStatus::Failure; + } + } + + return ObjectiveStatus::Undecided; + } + + ObjectiveStatus Objective::CheckParkValueBy() const + { + int32_t currentMonthYear = GetDate().GetMonthsElapsed(); + money64 objectiveParkValue = Currency; + money64 parkValue = getGameState().park.value; + + if (currentMonthYear == MONTH_COUNT * Year || AllowEarlyCompletion()) + { + if (parkValue >= objectiveParkValue) + { + return ObjectiveStatus::Success; + } + + if (currentMonthYear == MONTH_COUNT * Year) + { + return ObjectiveStatus::Failure; + } + } + + return ObjectiveStatus::Undecided; + } + + /** + * Checks if there are 10 rollercoasters of different subtype with + * excitement >= 600 . + * rct2: + **/ + ObjectiveStatus Objective::Check10RollerCoasters() const + { + auto rcs = 0; + BitSet type_already_counted; + for (const auto& ride : GetRideManager()) + { + if (ride.status == RideStatus::open && ride.ratings.excitement >= RideRating::make(6, 00) + && ride.subtype != kObjectEntryIndexNull) + { + auto rideEntry = ride.getRideEntry(); + if (rideEntry != nullptr) + { + if (RideEntryHasCategory(*rideEntry, RideCategory::rollerCoaster) && !type_already_counted[ride.subtype]) + { + type_already_counted[ride.subtype] = true; + rcs++; + } + } + } + } + if (rcs >= 10) + { + return ObjectiveStatus::Success; + } + + return ObjectiveStatus::Undecided; + } + + /** + * + * rct2: 0x0066A13C + */ + ObjectiveStatus Objective::CheckGuestsAndRating() const + { + auto& gameState = getGameState(); + if (gameState.park.rating < 700 && GetDate().GetMonthsElapsed() >= 1) + { + gameState.scenarioParkRatingWarningDays++; + if (gameState.scenarioParkRatingWarningDays == 1) + { + if (Config::Get().notifications.ParkRatingWarnings) + { + News::AddItemToQueue(News::ItemType::graph, STR_PARK_RATING_WARNING_4_WEEKS_REMAINING, 0, {}); + } + } + else if (gameState.scenarioParkRatingWarningDays == 8) + { + if (Config::Get().notifications.ParkRatingWarnings) + { + News::AddItemToQueue(News::ItemType::graph, STR_PARK_RATING_WARNING_3_WEEKS_REMAINING, 0, {}); + } + } + else if (gameState.scenarioParkRatingWarningDays == 15) + { + if (Config::Get().notifications.ParkRatingWarnings) + { + News::AddItemToQueue(News::ItemType::graph, STR_PARK_RATING_WARNING_2_WEEKS_REMAINING, 0, {}); + } + } + else if (gameState.scenarioParkRatingWarningDays == 22) + { + if (Config::Get().notifications.ParkRatingWarnings) + { + News::AddItemToQueue(News::ItemType::graph, STR_PARK_RATING_WARNING_1_WEEK_REMAINING, 0, {}); + } + } + else if (gameState.scenarioParkRatingWarningDays == 29) + { + News::AddItemToQueue(News::ItemType::graph, STR_PARK_HAS_BEEN_CLOSED_DOWN, 0, {}); + gameState.park.flags &= ~PARK_FLAGS_PARK_OPEN; + gameState.scenarioOptions.guestInitialHappiness = 50; + return ObjectiveStatus::Failure; + } + } + else if (gameState.scenarioCompletedCompanyValue != kCompanyValueOnFailedObjective) + { + gameState.scenarioParkRatingWarningDays = 0; + } + + if (gameState.park.rating >= 700) + if (gameState.park.numGuestsInPark >= NumGuests) + return ObjectiveStatus::Success; + + return ObjectiveStatus::Undecided; + } + + ObjectiveStatus Objective::CheckMonthlyRideIncome() const + { + money64 lastMonthRideIncome = getGameState().park.expenditureTable[1][EnumValue(ExpenditureType::parkRideTickets)]; + if (lastMonthRideIncome >= Currency) + { + return ObjectiveStatus::Success; + } + + return ObjectiveStatus::Undecided; + } + + /** + * Checks if there are 10 rollercoasters of different subtype with + * excitement > 700 and a minimum length; + * rct2: 0x0066A6B5 + */ + ObjectiveStatus Objective::Check10RollerCoastersLength() const + { + BitSet type_already_counted; + auto rcs = 0; + for (const auto& ride : GetRideManager()) + { + if (ride.status == RideStatus::open && ride.ratings.excitement >= RideRating::make(7, 00) + && ride.subtype != kObjectEntryIndexNull) + { + auto rideEntry = ride.getRideEntry(); + if (rideEntry != nullptr) + { + if (RideEntryHasCategory(*rideEntry, RideCategory::rollerCoaster) && !type_already_counted[ride.subtype]) + { + if (ToHumanReadableRideLength(ride.getTotalLength()) >= MinimumLength) + { + type_already_counted[ride.subtype] = true; + rcs++; + } + } + } + } + } + if (rcs >= 10) + { + return ObjectiveStatus::Success; + } + + return ObjectiveStatus::Undecided; + } + + ObjectiveStatus Objective::CheckFinish5RollerCoasters() const + { + // 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 != RideStatus::closed && ride.ratings.excitement >= MinimumExcitement) + { + auto rideEntry = ride.getRideEntry(); + if (rideEntry != nullptr) + { + if ((ride.lifecycleFlags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) + && RideEntryHasCategory(*rideEntry, RideCategory::rollerCoaster)) + { + rcs++; + } + } + } + } + if (rcs >= 5) + { + return ObjectiveStatus::Success; + } + + return ObjectiveStatus::Undecided; + } + + ObjectiveStatus Objective::CheckRepayLoanAndParkValue() const + { + const auto& gameState = getGameState(); + money64 parkValue = gameState.park.value; + money64 currentLoan = gameState.park.bankLoan; + + if (currentLoan <= 0 && parkValue >= Currency) + { + return ObjectiveStatus::Success; + } + + return ObjectiveStatus::Undecided; + } + + ObjectiveStatus Objective::CheckMonthlyFoodIncome() const + { + const auto* lastMonthExpenditure = getGameState().park.expenditureTable[1]; + auto lastMonthProfit = lastMonthExpenditure[EnumValue(ExpenditureType::shopSales)] + + lastMonthExpenditure[EnumValue(ExpenditureType::shopStock)] + + lastMonthExpenditure[EnumValue(ExpenditureType::foodDrinkSales)] + + lastMonthExpenditure[EnumValue(ExpenditureType::foodDrinkStock)]; + + if (lastMonthProfit >= Currency) + { + return ObjectiveStatus::Success; + } + + return ObjectiveStatus::Undecided; + } + + /** + * Checks the win/lose conditions of the current objective. + * rct2: 0x0066A4B2 + */ + ObjectiveStatus Objective::Check(GameState_t& gameState) const + { + if (gameState.scenarioCompletedCompanyValue != kMoney64Undefined) + { + return ObjectiveStatus::Undecided; + } + + switch (Type) + { + case ObjectiveType::guestsBy: + return CheckGuestsBy(); + case ObjectiveType::parkValueBy: + return CheckParkValueBy(); + case ObjectiveType::tenRollercoasters: + return Check10RollerCoasters(); + case ObjectiveType::guestsAndRating: + return CheckGuestsAndRating(); + case ObjectiveType::monthlyRideIncome: + return CheckMonthlyRideIncome(); + case ObjectiveType::tenRollercoastersLength: + return Check10RollerCoastersLength(); + case ObjectiveType::finishFiveRollercoasters: + return CheckFinish5RollerCoasters(); + case ObjectiveType::repayLoanAndParkValue: + return CheckRepayLoanAndParkValue(); + case ObjectiveType::monthlyFoodIncome: + return CheckMonthlyFoodIncome(); + default: + return ObjectiveStatus::Undecided; + } + } + + bool ObjectiveNeedsMoney(const ObjectiveType objective) + { + switch (objective) + { + case ObjectiveType::parkValueBy: + case ObjectiveType::monthlyRideIncome: + case ObjectiveType::repayLoanAndParkValue: + case ObjectiveType::monthlyFoodIncome: + return true; + default: + return false; + } + } +} // namespace OpenRCT2::Scenario diff --git a/src/openrct2/scenario/ScenarioObjective.h b/src/openrct2/scenario/ScenarioObjective.h new file mode 100644 index 0000000000..06c2e2e260 --- /dev/null +++ b/src/openrct2/scenario/ScenarioObjective.h @@ -0,0 +1,92 @@ +/***************************************************************************** + * Copyright (c) 2014-2025 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../core/Money.hpp" +#include "../localisation/StringIdType.h" +#include "../ride/RideRatings.h" + +namespace OpenRCT2 +{ + struct GameState_t; +} + +namespace OpenRCT2::Scenario +{ + enum class ObjectiveType : uint8_t + { + none, + guestsBy, + parkValueBy, + haveFun, + buildTheBest, + tenRollercoasters, + guestsAndRating, + monthlyRideIncome, + tenRollercoastersLength, + finishFiveRollercoasters, + repayLoanAndParkValue, + monthlyFoodIncome, + + count + }; + + bool ObjectiveNeedsMoney(const ObjectiveType objective); + + enum class ObjectiveStatus : uint8_t + { + Undecided, + Success, + Failure, + }; + + struct Objective + { + ObjectiveType Type; + uint8_t Year; + union + { + uint16_t NumGuests; + StringId RideId; + uint16_t MinimumLength; // For the "Build 10 coasters of minimum length" objective. + }; + union + { + money64 Currency; + RideRating_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 != ObjectiveType::monthlyRideIncome) || canAskMoneyForRides; + return objectiveAllowedByMoneyUsage && objectiveAllowedByPaymentSettings; + } + + ObjectiveStatus Check(GameState_t& gameState) 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; + }; +} // namespace OpenRCT2::Scenario diff --git a/src/openrct2/scenario/ScenarioRepository.h b/src/openrct2/scenario/ScenarioRepository.h index ebdb506683..feb4f13619 100644 --- a/src/openrct2/scenario/ScenarioRepository.h +++ b/src/openrct2/scenario/ScenarioRepository.h @@ -12,6 +12,7 @@ #include "../core/DateTime.h" #include "../core/Money.hpp" #include "../core/StringTypes.h" +#include "ScenarioObjective.h" #include @@ -52,7 +53,7 @@ struct ScenarioIndexEntry uint16_t ScenarioId; // Objective - uint8_t ObjectiveType; + OpenRCT2::Scenario::ObjectiveType ObjectiveType; uint8_t ObjectiveArg1; // years int64_t ObjectiveArg2; // money or excitement uint16_t ObjectiveArg3; // guests or rideID or coasterLength diff --git a/src/openrct2/scripting/bindings/game/ScContext.hpp b/src/openrct2/scripting/bindings/game/ScContext.hpp index 7166b5c99d..d5f8ddca86 100644 --- a/src/openrct2/scripting/bindings/game/ScContext.hpp +++ b/src/openrct2/scripting/bindings/game/ScContext.hpp @@ -16,6 +16,7 @@ #include "../../../interface/Screenshot.h" #include "../../../localisation/Formatting.h" #include "../../../object/ObjectManager.h" + #include "../../../scenario/Scenario.h" #include "../../Duktape.hpp" #include "../../HookEngine.h" #include "../../IconNames.hpp" diff --git a/src/openrct2/scripting/bindings/world/ScScenario.hpp b/src/openrct2/scripting/bindings/world/ScScenario.hpp index 1dbe99f188..96f06ecc15 100644 --- a/src/openrct2/scripting/bindings/world/ScScenario.hpp +++ b/src/openrct2/scripting/bindings/world/ScScenario.hpp @@ -14,26 +14,29 @@ #include "../../../Context.h" #include "../../../GameState.h" #include "../../../core/StringTypes.h" + #include "../../../scenario/Scenario.h" #include "../../../world/Park.h" #include "../../Duktape.hpp" #include "../../ScriptEngine.h" namespace OpenRCT2::Scripting { - static const DukEnumMap ScenarioObjectiveTypeMap( + using namespace OpenRCT2::Scenario; + + static const DukEnumMap ScenarioObjectiveTypeMap( { - { "none", OBJECTIVE_NONE }, - { "guestsBy", OBJECTIVE_GUESTS_BY }, - { "parkValueBy", OBJECTIVE_PARK_VALUE_BY }, - { "haveFun", OBJECTIVE_HAVE_FUN }, - { "buildTheBest", OBJECTIVE_BUILD_THE_BEST }, - { "10Rollercoasters", OBJECTIVE_10_ROLLERCOASTERS }, - { "guestsAndRating", OBJECTIVE_GUESTS_AND_RATING }, - { "monthlyRideIncome", OBJECTIVE_MONTHLY_RIDE_INCOME }, - { "10RollercoastersLength", OBJECTIVE_10_ROLLERCOASTERS_LENGTH }, - { "finish5Rollercoasters", OBJECTIVE_FINISH_5_ROLLERCOASTERS }, - { "repayLoanAndParkValue", OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE }, - { "monthlyFoodIncome", OBJECTIVE_MONTHLY_FOOD_INCOME }, + { "none", ObjectiveType::none }, + { "guestsBy", ObjectiveType::guestsBy }, + { "parkValueBy", ObjectiveType::parkValueBy }, + { "haveFun", ObjectiveType::haveFun }, + { "buildTheBest", ObjectiveType::buildTheBest }, + { "10Rollercoasters", ObjectiveType::tenRollercoasters }, + { "guestsAndRating", ObjectiveType::guestsAndRating }, + { "monthlyRideIncome", ObjectiveType::monthlyRideIncome }, + { "10RollercoastersLength", ObjectiveType::tenRollercoastersLength }, + { "finish5Rollercoasters", ObjectiveType::finishFiveRollercoasters }, + { "repayLoanAndParkValue", ObjectiveType::repayLoanAndParkValue }, + { "monthlyFoodIncome", ObjectiveType::monthlyFoodIncome }, }); class ScScenarioObjective @@ -53,8 +56,8 @@ namespace OpenRCT2::Scripting uint16_t guests_get() { auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_GUESTS_BY - || gameState.scenarioOptions.objective.Type == OBJECTIVE_GUESTS_AND_RATING) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::guestsBy + || gameState.scenarioOptions.objective.Type == ObjectiveType::guestsAndRating) { return gameState.scenarioOptions.objective.NumGuests; } @@ -65,8 +68,8 @@ namespace OpenRCT2::Scripting { ThrowIfGameStateNotMutable(); auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_GUESTS_BY - || gameState.scenarioOptions.objective.Type == OBJECTIVE_GUESTS_AND_RATING) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::guestsBy + || gameState.scenarioOptions.objective.Type == ObjectiveType::guestsAndRating) { gameState.scenarioOptions.objective.NumGuests = value; } @@ -75,8 +78,8 @@ namespace OpenRCT2::Scripting uint8_t year_get() { const auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_GUESTS_BY - || gameState.scenarioOptions.objective.Type == OBJECTIVE_PARK_VALUE_BY) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::guestsBy + || gameState.scenarioOptions.objective.Type == ObjectiveType::parkValueBy) { return gameState.scenarioOptions.objective.Year; } @@ -87,8 +90,8 @@ namespace OpenRCT2::Scripting { auto& gameState = getGameState(); ThrowIfGameStateNotMutable(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_GUESTS_BY - || gameState.scenarioOptions.objective.Type == OBJECTIVE_PARK_VALUE_BY) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::guestsBy + || gameState.scenarioOptions.objective.Type == ObjectiveType::parkValueBy) { gameState.scenarioOptions.objective.Year = value; } @@ -97,7 +100,7 @@ namespace OpenRCT2::Scripting uint16_t length_get() { const auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_10_ROLLERCOASTERS_LENGTH) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::tenRollercoastersLength) { return gameState.scenarioOptions.objective.NumGuests; } @@ -108,7 +111,7 @@ namespace OpenRCT2::Scripting { ThrowIfGameStateNotMutable(); auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_10_ROLLERCOASTERS_LENGTH) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::tenRollercoastersLength) { gameState.scenarioOptions.objective.NumGuests = value; } @@ -117,7 +120,7 @@ namespace OpenRCT2::Scripting money64 excitement_get() { const auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_FINISH_5_ROLLERCOASTERS) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::finishFiveRollercoasters) { return gameState.scenarioOptions.objective.Currency; } @@ -128,7 +131,7 @@ namespace OpenRCT2::Scripting { ThrowIfGameStateNotMutable(); auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_FINISH_5_ROLLERCOASTERS) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::finishFiveRollercoasters) { gameState.scenarioOptions.objective.Currency = value; } @@ -137,8 +140,8 @@ namespace OpenRCT2::Scripting money64 parkValue_get() { const auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_PARK_VALUE_BY - || gameState.scenarioOptions.objective.Type == OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::parkValueBy + || gameState.scenarioOptions.objective.Type == ObjectiveType::repayLoanAndParkValue) { return gameState.scenarioOptions.objective.Currency; } @@ -149,8 +152,8 @@ namespace OpenRCT2::Scripting { ThrowIfGameStateNotMutable(); auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_PARK_VALUE_BY - || gameState.scenarioOptions.objective.Type == OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::parkValueBy + || gameState.scenarioOptions.objective.Type == ObjectiveType::repayLoanAndParkValue) { gameState.scenarioOptions.objective.Currency = value; } @@ -159,8 +162,8 @@ namespace OpenRCT2::Scripting money64 monthlyIncome_get() { const auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_MONTHLY_RIDE_INCOME - || gameState.scenarioOptions.objective.Type == OBJECTIVE_MONTHLY_FOOD_INCOME) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::monthlyRideIncome + || gameState.scenarioOptions.objective.Type == ObjectiveType::monthlyFoodIncome) { return gameState.scenarioOptions.objective.Currency; } @@ -171,8 +174,8 @@ namespace OpenRCT2::Scripting { ThrowIfGameStateNotMutable(); auto& gameState = getGameState(); - if (gameState.scenarioOptions.objective.Type == OBJECTIVE_PARK_VALUE_BY - || gameState.scenarioOptions.objective.Type == OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE) + if (gameState.scenarioOptions.objective.Type == ObjectiveType::parkValueBy + || gameState.scenarioOptions.objective.Type == ObjectiveType::repayLoanAndParkValue) { gameState.scenarioOptions.objective.Currency = value; } diff --git a/src/openrct2/world/Climate.cpp b/src/openrct2/world/Climate.cpp index 4426f71efa..d1357307ee 100644 --- a/src/openrct2/world/Climate.cpp +++ b/src/openrct2/world/Climate.cpp @@ -22,6 +22,7 @@ #include "../object/ClimateObject.h" #include "../object/ObjectManager.h" #include "../profiling/Profiling.h" +#include "../scenario/Scenario.h" #include "../util/Util.h" #include "../windows/Intent.h" diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 344272f601..3ea3f7c1bb 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -33,6 +33,7 @@ #include "../ride/RideData.h" #include "../ride/RideManager.hpp" #include "../ride/ShopItem.h" +#include "../scenario/Scenario.h" #include "../scripting/ScriptEngine.h" #include "../ui/WindowManager.h" #include "../util/Util.h" @@ -313,7 +314,7 @@ namespace OpenRCT2::Park gameState.scenarioOptions.guestInitialHappiness = Park::CalculateGuestInitialHappiness(50); gameState.scenarioOptions.guestInitialHunger = 200; gameState.scenarioOptions.guestInitialThirst = 200; - gameState.scenarioOptions.objective.Type = OBJECTIVE_GUESTS_BY; + gameState.scenarioOptions.objective.Type = Scenario::ObjectiveType::guestsBy; gameState.scenarioOptions.objective.Year = 4; gameState.scenarioOptions.objective.NumGuests = 1000; gameState.scenarioOptions.landPrice = 90.00_GBP;