1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-04 13:42:55 +01:00

Merge pull request #12665 from Gymnasiast/refactor/objective-struct

Create Objective struct and use it for global objective
This commit is contained in:
Michael Steenbeek
2020-09-09 22:34:33 +02:00
committed by GitHub
12 changed files with 227 additions and 161 deletions

View File

@@ -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<uint8_t>(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);
}

View File

@@ -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();

View File

@@ -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<uint16_t>(gScenarioObjectiveNumGuests);
ft.Add<int16_t>(date_get_total_months(MONTH_OCTOBER, gScenarioObjectiveYear));
ft.Add<money32>(gScenarioObjectiveCurrency);
ft.Add<uint16_t>(gScenarioObjective.NumGuests);
ft.Add<int16_t>(date_get_total_months(MONTH_OCTOBER, gScenarioObjective.Year));
ft.Add<money32>(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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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()

View File

@@ -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));

View File

@@ -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;

View File

@@ -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<MAX_RIDE_OBJECTS> 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<int32_t>(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<MAX_RIDE_OBJECTS> 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<int32_t>(ExpenditureType::ShopSales)]
@@ -924,53 +933,61 @@ static void scenario_objective_check_monthly_food_income()
+ lastMonthExpenditure[static_cast<int32_t>(ExpenditureType::FoodDrinkSales)]
+ lastMonthExpenditure[static_cast<int32_t>(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)

View File

@@ -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

View File

@@ -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;