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

clang-format scenario

This commit is contained in:
clang-format
2018-06-22 23:14:50 +02:00
committed by Hielke Morsink
parent e8310d079d
commit 861715a169
6 changed files with 509 additions and 428 deletions

View File

@@ -7,12 +7,17 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../audio/audio.h"
#include "Scenario.h"
#include "../Cheats.h"
#include "../config/Config.h"
#include "../Context.h"
#include "../FileClassifier.h"
#include "../Game.h"
#include "../GameState.h"
#include "../OpenRCT2.h"
#include "../ParkImporter.h"
#include "../audio/audio.h"
#include "../config/Config.h"
#include "../interface/Viewport.h"
#include "../localisation/Date.h"
#include "../localisation/Localisation.h"
@@ -24,14 +29,14 @@
#include "../network/network.h"
#include "../object/Object.h"
#include "../object/ObjectList.h"
#include "../OpenRCT2.h"
#include "../ParkImporter.h"
#include "../peep/Staff.h"
#include "../platform/platform.h"
#include "../rct1/RCT1.h"
#include "../ride/Ride.h"
#include "../ride/Track.h"
#include "../util/SawyerCoding.h"
#include "../util/Util.h"
#include "../windows/Intent.h"
#include "../world/Climate.h"
#include "../world/Map.h"
#include "../world/Park.h"
@@ -40,20 +45,11 @@
#include "../world/Water.h"
#include "ScenarioRepository.h"
#include "ScenarioSources.h"
#include "Scenario.h"
#include "../Context.h"
#include "../ride/Track.h"
#include "../windows/Intent.h"
const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT] = {
STR_BEGINNER_PARKS,
STR_CHALLENGING_PARKS,
STR_EXPERT_PARKS,
STR_REAL_PARKS,
STR_OTHER_PARKS,
STR_BEGINNER_PARKS, STR_CHALLENGING_PARKS, STR_EXPERT_PARKS, STR_REAL_PARKS, STR_OTHER_PARKS,
STR_DLC_PARKS,
STR_BUILD_YOUR_OWN_PARKS,
STR_DLC_PARKS, STR_BUILD_YOUR_OWN_PARKS,
};
rct_s6_info gS6Info;
@@ -94,7 +90,6 @@ void scenario_begin()
gScenarioSrand0 ^= platform_get_ticks();
gScenarioSrand1 ^= platform_get_ticks();
gParkFlags &= ~PARK_FLAGS_NO_MONEY;
if (gParkFlags & PARK_FLAGS_NO_MONEY_SCENARIO)
gParkFlags |= PARK_FLAGS_NO_MONEY;
@@ -119,21 +114,27 @@ void scenario_begin()
scenario_normalise_name(normalisedName, sizeof(normalisedName), gS6Info.name);
rct_string_id localisedStringIds[3];
if (language_get_localised_scenario_strings(normalisedName, localisedStringIds)) {
if (localisedStringIds[0] != STR_NONE) {
if (language_get_localised_scenario_strings(normalisedName, localisedStringIds))
{
if (localisedStringIds[0] != STR_NONE)
{
safe_strcpy(gScenarioName, language_get_string(localisedStringIds[0]), 32);
}
if (localisedStringIds[1] != STR_NONE) {
if (localisedStringIds[1] != STR_NONE)
{
park_set_name(language_get_string(localisedStringIds[1]));
}
if (localisedStringIds[2] != STR_NONE) {
if (localisedStringIds[2] != STR_NONE)
{
safe_strcpy(gScenarioDetails, language_get_string(localisedStringIds[2]), 256);
}
}
else {
auto stex = (rct_stex_entry *)object_entry_get_chunk(OBJECT_TYPE_SCENARIO_TEXT, 0);
if (stex != nullptr) {
char *buffer = gCommonStringFormatBuffer;
else
{
auto stex = (rct_stex_entry*)object_entry_get_chunk(OBJECT_TYPE_SCENARIO_TEXT, 0);
if (stex != nullptr)
{
char* buffer = gCommonStringFormatBuffer;
// Set localised park name
format_string(buffer, 256, stex->park_name, nullptr);
@@ -180,7 +181,8 @@ void scenario_begin()
gParkRatingCasualtyPenalty = 0;
// Open park with free entry when there is no money
if (gParkFlags & PARK_FLAGS_NO_MONEY) {
if (gParkFlags & PARK_FLAGS_NO_MONEY)
{
gParkFlags |= PARK_FLAGS_PARK_OPEN;
gParkEntranceFee = 0;
}
@@ -231,7 +233,7 @@ void scenario_success()
*
* rct2: 0x006695E8
*/
void scenario_success_submit_name(const char *name)
void scenario_success_submit_name(const char* name)
{
if (scenario_repository_try_record_highscore(gScenarioFileName, gScenarioCompanyValueRecord, name))
{
@@ -250,14 +252,17 @@ static void scenario_entrance_fee_too_high_check()
money16 totalRideValueForMoney = gTotalRideValueForMoney;
money16 max_fee = totalRideValueForMoney + (totalRideValueForMoney / 2);
if ((gParkFlags & PARK_FLAGS_PARK_OPEN) && park_get_entrance_fee() > max_fee) {
for (int32_t i = 0; i < MAX_PARK_ENTRANCES && gParkEntrances[i].x != LOCATION_NULL; i++) {
if ((gParkFlags & PARK_FLAGS_PARK_OPEN) && park_get_entrance_fee() > max_fee)
{
for (int32_t i = 0; i < MAX_PARK_ENTRANCES && gParkEntrances[i].x != LOCATION_NULL; i++)
{
x = gParkEntrances[i].x + 16;
y = gParkEntrances[i].y + 16;
}
uint32_t packed_xy = (y << 16) | x;
if (gConfigNotifications.park_warnings) {
if (gConfigNotifications.park_warnings)
{
news_item_add_to_queue(NEWS_ITEM_BLANK, STR_ENTRANCE_FEE_TOO_HI, packed_xy);
}
}
@@ -265,31 +270,34 @@ static void scenario_entrance_fee_too_high_check()
void scenario_autosave_check()
{
if (gLastAutoSaveUpdate == AUTOSAVE_PAUSE) return;
if (gLastAutoSaveUpdate == AUTOSAVE_PAUSE)
return;
// Milliseconds since last save
uint32_t timeSinceSave = platform_get_ticks() - gLastAutoSaveUpdate;
bool shouldSave = false;
switch (gConfigGeneral.autosave_frequency) {
case AUTOSAVE_EVERY_MINUTE:
shouldSave = timeSinceSave >= 1 * 60 * 1000;
break;
case AUTOSAVE_EVERY_5MINUTES:
shouldSave = timeSinceSave >= 5 * 60 * 1000;
break;
case AUTOSAVE_EVERY_15MINUTES:
shouldSave = timeSinceSave >= 15 * 60 * 1000;
break;
case AUTOSAVE_EVERY_30MINUTES:
shouldSave = timeSinceSave >= 30 * 60 * 1000;
break;
case AUTOSAVE_EVERY_HOUR:
shouldSave = timeSinceSave >= 60 * 60 * 1000;
break;
switch (gConfigGeneral.autosave_frequency)
{
case AUTOSAVE_EVERY_MINUTE:
shouldSave = timeSinceSave >= 1 * 60 * 1000;
break;
case AUTOSAVE_EVERY_5MINUTES:
shouldSave = timeSinceSave >= 5 * 60 * 1000;
break;
case AUTOSAVE_EVERY_15MINUTES:
shouldSave = timeSinceSave >= 15 * 60 * 1000;
break;
case AUTOSAVE_EVERY_30MINUTES:
shouldSave = timeSinceSave >= 30 * 60 * 1000;
break;
case AUTOSAVE_EVERY_HOUR:
shouldSave = timeSinceSave >= 60 * 60 * 1000;
break;
}
if (shouldSave) {
if (shouldSave)
{
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
game_autosave();
}
@@ -299,18 +307,19 @@ static void scenario_day_update()
{
finance_update_daily_profit();
peep_update_days_in_queue();
switch (gScenarioObjectiveType) {
case OBJECTIVE_10_ROLLERCOASTERS:
case OBJECTIVE_GUESTS_AND_RATING:
case OBJECTIVE_10_ROLLERCOASTERS_LENGTH:
case OBJECTIVE_FINISH_5_ROLLERCOASTERS:
case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE:
scenario_objective_check();
break;
default:
if (gConfigGeneral.allow_early_completion)
switch (gScenarioObjectiveType)
{
case OBJECTIVE_10_ROLLERCOASTERS:
case OBJECTIVE_GUESTS_AND_RATING:
case OBJECTIVE_10_ROLLERCOASTERS_LENGTH:
case OBJECTIVE_FINISH_5_ROLLERCOASTERS:
case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE:
scenario_objective_check();
break;
break;
default:
if (gConfigGeneral.allow_early_completion)
scenario_objective_check();
break;
}
// Lower the casualty penalty
@@ -333,11 +342,13 @@ static void scenario_week_update()
ride_check_all_reachable();
ride_update_favourited_stat();
auto water_type = (rct_water_type *)object_entry_get_chunk(OBJECT_TYPE_WATER, 0);
auto water_type = (rct_water_type*)object_entry_get_chunk(OBJECT_TYPE_WATER, 0);
if (month <= MONTH_APRIL && water_type != nullptr && water_type->flags & WATER_FLAGS_ALLOW_DUCKS) {
if (month <= MONTH_APRIL && water_type != nullptr && water_type->flags & WATER_FLAGS_ALLOW_DUCKS)
{
// 100 attempts at finding some water to create a few ducks at
for (int32_t i = 0; i < 100; i++) {
for (int32_t i = 0; i < 100; i++)
{
if (scenario_create_ducks())
break;
}
@@ -362,23 +373,34 @@ static void scenario_update_daynight_cycle()
float currentDayNightCycle = gDayNightCycle;
gDayNightCycle = 0;
if (gScreenFlags == SCREEN_FLAGS_PLAYING && gConfigGeneral.day_night_cycle) {
if (gScreenFlags == SCREEN_FLAGS_PLAYING && gConfigGeneral.day_night_cycle)
{
float monthFraction = gDateMonthTicks / (float)0x10000;
if (monthFraction < (1 / 8.0f)) {
if (monthFraction < (1 / 8.0f))
{
gDayNightCycle = 0.0f;
} else if (monthFraction < (3 / 8.0f)) {
}
else if (monthFraction < (3 / 8.0f))
{
gDayNightCycle = (monthFraction - (1 / 8.0f)) / (2 / 8.0f);
} else if (monthFraction < (5 / 8.0f)) {
}
else if (monthFraction < (5 / 8.0f))
{
gDayNightCycle = 1.0f;
} else if (monthFraction < (7 / 8.0f)) {
}
else if (monthFraction < (7 / 8.0f))
{
gDayNightCycle = 1.0f - ((monthFraction - (5 / 8.0f)) / (2 / 8.0f));
} else {
}
else
{
gDayNightCycle = 0.0f;
}
}
// Only update palette if day / night cycle has changed
if (gDayNightCycle != currentDayNightCycle) {
if (gDayNightCycle != currentDayNightCycle)
{
platform_update_palette(gGamePalette, 10, 236);
}
}
@@ -425,7 +447,7 @@ static int32_t scenario_create_ducks()
x = (x + 64) * 32;
y = (y + 64) * 32;
if (!map_is_location_in_park({x, y}))
if (!map_is_location_in_park({ x, y }))
return 0;
centreWaterZ = (tile_element_height(x, y) >> 16) & 0xFFFF;
@@ -436,8 +458,10 @@ static int32_t scenario_create_ducks()
x2 = x - (32 * 3);
y2 = y - (32 * 3);
c = 0;
for (i = 0; i < 7; i++) {
for (j = 0; j < 7; j++) {
for (i = 0; i < 7; i++)
{
for (j = 0; j < 7; j++)
{
waterZ = (tile_element_height(x2, y2) >> 16) & 0xFFFF;
if (waterZ == centreWaterZ)
c++;
@@ -456,7 +480,8 @@ static int32_t scenario_create_ducks()
x += 16;
y += 16;
c = (scenario_rand() & 3) + 2;
for (i = 0; i < c; i++) {
for (i = 0; i < c; i++)
{
r = scenario_rand();
x2 = (r >> 16) & 0x7F;
y2 = (r & 0xFFFF) & 0x7F;
@@ -475,10 +500,10 @@ static int32_t scenario_create_ducks()
#ifndef DEBUG_DESYNC
uint32_t scenario_rand()
#else
static FILE *fp = nullptr;
static const char *realm = "LC";
static FILE* fp = nullptr;
static const char* realm = "LC";
uint32_t dbg_scenario_rand(const char *file, const char *function, const uint32_t line, const void *data)
uint32_t dbg_scenario_rand(const char* file, const char* function, const uint32_t line, const void* data)
#endif
{
uint32_t originalSrand0 = gScenarioSrand0;
@@ -510,7 +535,8 @@ uint32_t dbg_scenario_rand(const char *file, const char *function, const uint32_
{
fprintf(fp, "Tick: %d, Rand: %08X - REF: %s:%u %s (%p)\n", gCurrentTicks, gScenarioSrand1, file, line, function, data);
}
if (!gInUpdateCode && !gInMapInitCode) {
if (!gInUpdateCode && !gInMapInitCode)
{
log_warning("scenario_rand called from outside game update");
assert(false);
}
@@ -520,7 +546,7 @@ uint32_t dbg_scenario_rand(const char *file, const char *function, const uint32_
}
#ifdef DEBUG_DESYNC
void dbg_report_desync(uint32_t tick, uint32_t srand0, uint32_t server_srand0, const char *clientHash, const char *serverHash)
void dbg_report_desync(uint32_t tick, uint32_t srand0, uint32_t server_srand0, const char* clientHash, const char* serverHash)
{
if (fp == nullptr)
{
@@ -539,24 +565,29 @@ void dbg_report_desync(uint32_t tick, uint32_t srand0, uint32_t server_srand0, c
{
const bool sprites_mismatch = serverHash[0] != '\0' && strcmp(clientHash, serverHash);
fprintf(fp, "[%s] !! DESYNC !! Tick: %d, Client Hash: %s, Server Hash: %s, Client Rand: %08X, Server Rand: %08X - %s\n", realm,
tick,
clientHash,
( (serverHash[0] != '\0') ? serverHash : "<NONE:0>" ),
srand0,
server_srand0,
(sprites_mismatch ? "Sprite hash mismatch" : "scenario rand mismatch"));
fprintf(
fp,
"[%s] !! DESYNC !! Tick: %d, Client Hash: %s, Server Hash: %s, Client Rand: %08X, Server Rand: %08X - %s\n",
realm,
tick,
clientHash,
((serverHash[0] != '\0') ? serverHash : "<NONE:0>"),
srand0,
server_srand0,
(sprites_mismatch ? "Sprite hash mismatch" : "scenario rand mismatch"));
}
}
#endif
uint32_t scenario_rand_max(uint32_t max)
{
if (max < 2) return 0;
if (max < 2)
return 0;
if ((max & (max - 1)) == 0)
return scenario_rand() & (max - 1);
uint32_t rand, cap = ~((uint32_t)0) - (~((uint32_t)0) % max) - 1;
do {
do
{
rand = scenario_rand();
} while (rand > cap);
return rand % max;
@@ -570,18 +601,16 @@ static bool scenario_prepare_rides_for_save()
{
int32_t isFiveCoasterObjective = gScenarioObjectiveType == OBJECTIVE_FINISH_5_ROLLERCOASTERS;
int32_t i;
Ride * ride;
Ride* ride;
uint8_t rcs = 0;
FOR_ALL_RIDES(i, ride)
FOR_ALL_RIDES (i, ride)
{
const rct_ride_entry * rideEntry = get_ride_entry(ride->subtype);
const rct_ride_entry* rideEntry = get_ride_entry(ride->subtype);
// If there are more than 5 roller coasters, only mark the first five.
if (isFiveCoasterObjective &&
rideEntry != nullptr &&
(ride_entry_has_category(rideEntry, RIDE_CATEGORY_ROLLERCOASTER) &&
rcs < 5))
if (isFiveCoasterObjective && rideEntry != nullptr
&& (ride_entry_has_category(rideEntry, RIDE_CATEGORY_ROLLERCOASTER) && rcs < 5))
{
ride->lifecycle_flags |= RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK;
rcs++;
@@ -627,8 +656,7 @@ static bool scenario_prepare_rides_for_save()
it.element->flags &= ~TILE_ELEMENT_FLAG_INDESTRUCTIBLE_TRACK_PIECE;
}
}
}
while (tile_element_iterator_next(&it));
} while (tile_element_iterator_next(&it));
return true;
}
@@ -641,8 +669,9 @@ bool scenario_prepare_for_save()
{
gS6Info.entry.flags = 255;
auto stex = (rct_stex_entry *)object_entry_get_chunk(OBJECT_TYPE_SCENARIO_TEXT, 0);
if (stex != nullptr) {
auto stex = (rct_stex_entry*)object_entry_get_chunk(OBJECT_TYPE_SCENARIO_TEXT, 0);
if (stex != nullptr)
{
char buffer[256];
format_string(buffer, 256, stex->scenario_name, nullptr);
safe_strcpy(gS6Info.name, buffer, sizeof(gS6Info.name));
@@ -676,19 +705,24 @@ bool scenario_prepare_for_save()
/**
* Modifies the given S6 data so that ghost elements, rides with no track elements or unused banners / user strings are saved.
*/
void scenario_fix_ghosts(rct_s6_data *s6)
void scenario_fix_ghosts(rct_s6_data* s6)
{
// Remove all ghost elements
rct_tile_element *destinationElement = s6->tile_elements;
rct_tile_element* destinationElement = s6->tile_elements;
for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) {
for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) {
rct_tile_element *originalElement = map_get_first_element_at(x, y);
do {
if (originalElement->flags & TILE_ELEMENT_FLAG_GHOST) {
for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++)
{
for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++)
{
rct_tile_element* originalElement = map_get_first_element_at(x, y);
do
{
if (originalElement->flags & TILE_ELEMENT_FLAG_GHOST)
{
BannerIndex bannerIndex = tile_element_get_banner_index(originalElement);
if (bannerIndex != BANNER_INDEX_NULL) {
rct_banner *banner = &s6->banners[bannerIndex];
if (bannerIndex != BANNER_INDEX_NULL)
{
rct_banner* banner = &s6->banners[bannerIndex];
if (banner->type != BANNER_NULL)
{
banner->type = BANNER_NULL;
@@ -696,7 +730,9 @@ void scenario_fix_ghosts(rct_s6_data *s6)
s6->custom_strings[(banner->string_idx % RCT12_MAX_USER_STRINGS)][0] = 0;
}
}
} else {
}
else
{
*destinationElement++ = *originalElement;
}
} while (!(originalElement++)->IsLastForTile());
@@ -707,14 +743,16 @@ void scenario_fix_ghosts(rct_s6_data *s6)
}
}
void scenario_remove_trackless_rides(rct_s6_data *s6)
void scenario_remove_trackless_rides(rct_s6_data* s6)
{
bool rideHasTrack[MAX_RIDES];
ride_all_has_any_track_elements(rideHasTrack);
for (int32_t i = 0; i < RCT12_MAX_RIDES_IN_PARK; i++) {
rct2_ride * ride = &s6->rides[i];
for (int32_t i = 0; i < RCT12_MAX_RIDES_IN_PARK; i++)
{
rct2_ride* ride = &s6->rides[i];
if (rideHasTrack[i] || ride->type == RIDE_TYPE_NULL) {
if (rideHasTrack[i] || ride->type == RIDE_TYPE_NULL)
{
continue;
}
@@ -734,11 +772,14 @@ static void scenario_objective_check_guests_by()
int16_t objectiveGuests = gScenarioObjectiveNumGuests;
int16_t currentMonthYear = gDateMonthsElapsed;
if (currentMonthYear == MONTH_COUNT * objectiveYear || gConfigGeneral.allow_early_completion) {
if (parkRating >= 600 && guestsInPark >= objectiveGuests) {
if (currentMonthYear == MONTH_COUNT * objectiveYear || gConfigGeneral.allow_early_completion)
{
if (parkRating >= 600 && guestsInPark >= objectiveGuests)
{
scenario_success();
}
else if (currentMonthYear == MONTH_COUNT * objectiveYear) {
else if (currentMonthYear == MONTH_COUNT * objectiveYear)
{
scenario_failure();
}
}
@@ -751,21 +792,24 @@ static void scenario_objective_check_park_value_by()
money32 objectiveParkValue = gScenarioObjectiveCurrency;
money32 parkValue = gParkValue;
if (currentMonthYear == MONTH_COUNT * objectiveYear || gConfigGeneral.allow_early_completion) {
if (parkValue >= objectiveParkValue) {
if (currentMonthYear == MONTH_COUNT * objectiveYear || gConfigGeneral.allow_early_completion)
{
if (parkValue >= objectiveParkValue)
{
scenario_success();
}
else if (currentMonthYear == MONTH_COUNT * objectiveYear) {
else if (currentMonthYear == MONTH_COUNT * objectiveYear)
{
scenario_failure();
}
}
}
/**
* Checks if there are 10 rollercoasters of different subtype with
* excitement >= 600 .
* rct2:
**/
* Checks if there are 10 rollercoasters of different subtype with
* excitement >= 600 .
* rct2:
**/
static void scenario_objective_check_10_rollercoasters()
{
int32_t i, rcs = 0;
@@ -774,17 +818,19 @@ static void scenario_objective_check_10_rollercoasters()
memset(type_already_counted, 0, 256);
FOR_ALL_RIDES(i, ride) {
FOR_ALL_RIDES (i, ride)
{
uint8_t subtype_id = ride->subtype;
rct_ride_entry *rideEntry = get_ride_entry(subtype_id);
if (rideEntry == nullptr) {
rct_ride_entry* rideEntry = get_ride_entry(subtype_id);
if (rideEntry == nullptr)
{
continue;
}
if (rideEntry != nullptr &&
ride_entry_has_category(rideEntry, RIDE_CATEGORY_ROLLERCOASTER) &&
ride->status == RIDE_STATUS_OPEN &&
ride->excitement >= RIDE_RATING(6,00) && type_already_counted[subtype_id] == 0){
if (rideEntry != nullptr && ride_entry_has_category(rideEntry, RIDE_CATEGORY_ROLLERCOASTER)
&& ride->status == RIDE_STATUS_OPEN && ride->excitement >= RIDE_RATING(6, 00)
&& type_already_counted[subtype_id] == 0)
{
type_already_counted[subtype_id]++;
rcs++;
}
@@ -800,31 +846,47 @@ static void scenario_objective_check_10_rollercoasters()
*/
static void scenario_objective_check_guests_and_rating()
{
if (gParkRating < 700 && gDateMonthsElapsed >= 1) {
if (gParkRating < 700 && gDateMonthsElapsed >= 1)
{
gScenarioParkRatingWarningDays++;
if (gScenarioParkRatingWarningDays == 1) {
if (gConfigNotifications.park_rating_warnings) {
if (gScenarioParkRatingWarningDays == 1)
{
if (gConfigNotifications.park_rating_warnings)
{
news_item_add_to_queue(NEWS_ITEM_GRAPH, STR_PARK_RATING_WARNING_4_WEEKS_REMAINING, 0);
}
} else if (gScenarioParkRatingWarningDays == 8) {
if (gConfigNotifications.park_rating_warnings) {
}
else if (gScenarioParkRatingWarningDays == 8)
{
if (gConfigNotifications.park_rating_warnings)
{
news_item_add_to_queue(NEWS_ITEM_GRAPH, STR_PARK_RATING_WARNING_3_WEEKS_REMAINING, 0);
}
} else if (gScenarioParkRatingWarningDays == 15) {
if (gConfigNotifications.park_rating_warnings) {
}
else if (gScenarioParkRatingWarningDays == 15)
{
if (gConfigNotifications.park_rating_warnings)
{
news_item_add_to_queue(NEWS_ITEM_GRAPH, STR_PARK_RATING_WARNING_2_WEEKS_REMAINING, 0);
}
} else if (gScenarioParkRatingWarningDays == 22) {
if (gConfigNotifications.park_rating_warnings) {
}
else if (gScenarioParkRatingWarningDays == 22)
{
if (gConfigNotifications.park_rating_warnings)
{
news_item_add_to_queue(NEWS_ITEM_GRAPH, STR_PARK_RATING_WARNING_1_WEEK_REMAINING, 0);
}
} else if (gScenarioParkRatingWarningDays == 29) {
}
else if (gScenarioParkRatingWarningDays == 29)
{
news_item_add_to_queue(NEWS_ITEM_GRAPH, STR_PARK_HAS_BEEN_CLOSED_DOWN, 0);
gParkFlags &= ~PARK_FLAGS_PARK_OPEN;
scenario_failure();
gGuestInitialHappiness = 50;
}
} else if (gScenarioCompletedCompanyValue != (money32)0x80000001) {
}
else if (gScenarioCompletedCompanyValue != (money32)0x80000001)
{
gScenarioParkRatingWarningDays = 0;
}
@@ -836,7 +898,8 @@ static void scenario_objective_check_guests_and_rating()
static void scenario_objective_check_monthly_ride_income()
{
money32 lastMonthRideIncome = gExpenditureTable[1][RCT_EXPENDITURE_TYPE_PARK_RIDE_TICKETS];
if (lastMonthRideIncome >= gScenarioObjectiveCurrency) {
if (lastMonthRideIncome >= gScenarioObjectiveCurrency)
{
scenario_success();
}
}
@@ -855,17 +918,19 @@ static void scenario_objective_check_10_rollercoasters_length()
memset(type_already_counted, 0, 256);
FOR_ALL_RIDES(i, ride) {
FOR_ALL_RIDES (i, ride)
{
uint8_t subtype_id = ride->subtype;
rct_ride_entry *rideEntry = get_ride_entry(subtype_id);
if (rideEntry == nullptr) {
rct_ride_entry* rideEntry = get_ride_entry(subtype_id);
if (rideEntry == nullptr)
{
continue;
}
if (ride_entry_has_category(rideEntry, RIDE_CATEGORY_ROLLERCOASTER) &&
ride->status == RIDE_STATUS_OPEN &&
ride->excitement >= RIDE_RATING(7,00) && type_already_counted[subtype_id] == 0){
if ((ride_get_total_length(ride) >> 16) > objective_length) {
if (ride_entry_has_category(rideEntry, RIDE_CATEGORY_ROLLERCOASTER) && ride->status == RIDE_STATUS_OPEN
&& ride->excitement >= RIDE_RATING(7, 00) && type_already_counted[subtype_id] == 0)
{
if ((ride_get_total_length(ride) >> 16) > objective_length)
{
type_already_counted[subtype_id]++;
rcs++;
}
@@ -883,19 +948,18 @@ static void scenario_objective_check_finish_5_rollercoasters()
// 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.
int32_t i;
Ride * ride;
Ride* ride;
int32_t rcs = 0;
FOR_ALL_RIDES(i, ride)
FOR_ALL_RIDES (i, ride)
{
const rct_ride_entry * rideEntry = get_ride_entry(ride->subtype);
const rct_ride_entry* rideEntry = get_ride_entry(ride->subtype);
if (rideEntry == nullptr)
{
continue;
}
if (ride->status != RIDE_STATUS_CLOSED &&
ride->excitement >= objectiveRideExcitement &&
(ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) && // Set on partially finished coasters
if (ride->status != RIDE_STATUS_CLOSED && ride->excitement >= objectiveRideExcitement
&& (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) && // Set on partially finished coasters
ride_entry_has_category(rideEntry, RIDE_CATEGORY_ROLLERCOASTER))
rcs++;
}
@@ -916,14 +980,13 @@ static void scenario_objective_check_replay_loan_and_park_value()
static void scenario_objective_check_monthly_food_income()
{
money32 * lastMonthExpenditure = gExpenditureTable[1];
int32_t lastMonthProfit =
lastMonthExpenditure[RCT_EXPENDITURE_TYPE_SHOP_SHOP_SALES] +
lastMonthExpenditure[RCT_EXPENDITURE_TYPE_SHOP_STOCK] +
lastMonthExpenditure[RCT_EXPENDITURE_TYPE_FOODDRINK_SALES] +
lastMonthExpenditure[RCT_EXPENDITURE_TYPE_FOODDRINK_STOCK];
money32* lastMonthExpenditure = gExpenditureTable[1];
int32_t lastMonthProfit = lastMonthExpenditure[RCT_EXPENDITURE_TYPE_SHOP_SHOP_SALES]
+ lastMonthExpenditure[RCT_EXPENDITURE_TYPE_SHOP_STOCK] + lastMonthExpenditure[RCT_EXPENDITURE_TYPE_FOODDRINK_SALES]
+ lastMonthExpenditure[RCT_EXPENDITURE_TYPE_FOODDRINK_STOCK];
if (lastMonthProfit >= gScenarioObjectiveCurrency) {
if (lastMonthProfit >= gScenarioObjectiveCurrency)
{
scenario_success();
}
}
@@ -934,38 +997,39 @@ static void scenario_objective_check_monthly_food_income()
*/
static void scenario_objective_check()
{
if (gScenarioCompletedCompanyValue != MONEY32_UNDEFINED) {
if (gScenarioCompletedCompanyValue != MONEY32_UNDEFINED)
{
return;
}
switch (gScenarioObjectiveType) {
case OBJECTIVE_GUESTS_BY:
scenario_objective_check_guests_by();
break;
case OBJECTIVE_PARK_VALUE_BY:
scenario_objective_check_park_value_by();
break;
case OBJECTIVE_10_ROLLERCOASTERS:
scenario_objective_check_10_rollercoasters();
break;
case OBJECTIVE_GUESTS_AND_RATING:
scenario_objective_check_guests_and_rating();
break;
case OBJECTIVE_MONTHLY_RIDE_INCOME:
scenario_objective_check_monthly_ride_income();
break;
case OBJECTIVE_10_ROLLERCOASTERS_LENGTH:
scenario_objective_check_10_rollercoasters_length();
break;
case OBJECTIVE_FINISH_5_ROLLERCOASTERS:
scenario_objective_check_finish_5_rollercoasters();
break;
case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE:
scenario_objective_check_replay_loan_and_park_value();
break;
case OBJECTIVE_MONTHLY_FOOD_INCOME:
scenario_objective_check_monthly_food_income();
break;
switch (gScenarioObjectiveType)
{
case OBJECTIVE_GUESTS_BY:
scenario_objective_check_guests_by();
break;
case OBJECTIVE_PARK_VALUE_BY:
scenario_objective_check_park_value_by();
break;
case OBJECTIVE_10_ROLLERCOASTERS:
scenario_objective_check_10_rollercoasters();
break;
case OBJECTIVE_GUESTS_AND_RATING:
scenario_objective_check_guests_and_rating();
break;
case OBJECTIVE_MONTHLY_RIDE_INCOME:
scenario_objective_check_monthly_ride_income();
break;
case OBJECTIVE_10_ROLLERCOASTERS_LENGTH:
scenario_objective_check_10_rollercoasters_length();
break;
case OBJECTIVE_FINISH_5_ROLLERCOASTERS:
scenario_objective_check_finish_5_rollercoasters();
break;
case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE:
scenario_objective_check_replay_loan_and_park_value();
break;
case OBJECTIVE_MONTHLY_FOOD_INCOME:
scenario_objective_check_monthly_food_income();
break;
}
}

View File

@@ -30,12 +30,13 @@ struct ParkLoadResult;
* SV6/SC6 header chunk
* size: 0x20
*/
struct rct_s6_header {
uint8_t type; // 0x00
uint8_t classic_flag; // 0x01
uint16_t num_packed_objects; // 0x02
uint32_t version; // 0x04
uint32_t magic_number; // 0x08
struct rct_s6_header
{
uint8_t type; // 0x00
uint8_t classic_flag; // 0x01
uint16_t num_packed_objects; // 0x02
uint32_t version; // 0x04
uint32_t magic_number; // 0x08
uint8_t pad_0C[0x14];
};
assert_struct_size(rct_s6_header, 0x20);
@@ -44,21 +45,23 @@ assert_struct_size(rct_s6_header, 0x20);
* SC6 information chunk
* size: 0x198
*/
struct rct_s6_info {
struct rct_s6_info
{
uint8_t editor_step;
uint8_t category; // 0x01
uint8_t objective_type; // 0x02
uint8_t objective_arg_1; // 0x03
int32_t objective_arg_2; // 0x04
int16_t objective_arg_3; // 0x08
uint8_t category; // 0x01
uint8_t objective_type; // 0x02
uint8_t objective_arg_1; // 0x03
int32_t objective_arg_2; // 0x04
int16_t objective_arg_3; // 0x08
uint8_t pad_00A[0x3E];
char name[64]; // 0x48
char details[256]; // 0x88
rct_object_entry entry; // 0x188
char name[64]; // 0x48
char details[256]; // 0x88
rct_object_entry entry; // 0x188
};
assert_struct_size(rct_s6_info, 0x198);
enum SCENARIO_SOURCE {
enum SCENARIO_SOURCE
{
SCENARIO_SOURCE_RCT1,
SCENARIO_SOURCE_RCT1_AA,
SCENARIO_SOURCE_RCT1_LL,
@@ -69,16 +72,18 @@ enum SCENARIO_SOURCE {
SCENARIO_SOURCE_OTHER,
};
struct rct_stex_entry {
rct_string_id scenario_name; // 0x00
rct_string_id park_name; // 0x02
rct_string_id details; // 0x04
struct rct_stex_entry
{
rct_string_id scenario_name; // 0x00
rct_string_id park_name; // 0x02
rct_string_id details; // 0x04
uint8_t var_06;
};
assert_struct_size(rct_stex_entry, 7);
// This will be useful for backwards compatibility
struct rct_s6_data {
struct rct_s6_data
{
// SC6[0]
rct_s6_header header;
@@ -281,7 +286,7 @@ struct rct_s6_data {
uint8_t current_rain_level;
uint8_t next_rain_level;
rct12_news_item news_items[RCT12_MAX_NEWS_ITEMS];
char rct1_scenario_name[62]; // Unused in RCT2
char rct1_scenario_name[62]; // Unused in RCT2
uint16_t rct1_scenario_slot_index; // Unused in RCT2
uint32_t rct1_scenario_flags; // Unused in RCT2
uint16_t wide_path_tile_loop_x;
@@ -291,13 +296,15 @@ struct rct_s6_data {
assert_struct_size(rct_s6_data, 0x46b44a);
#pragma pack(pop)
enum {
enum
{
SCENARIO_FLAGS_VISIBLE = (1 << 0),
SCENARIO_FLAGS_COMPLETED = (1 << 1),
SCENARIO_FLAGS_SIXFLAGS = (1 << 2)
};
enum {
enum
{
S6_TYPE_SAVEDGAME,
S6_TYPE_SCENARIO
};
@@ -305,7 +312,8 @@ enum {
#define S6_RCT2_VERSION 120001
#define S6_MAGIC_NUMBER 0x00031144
enum {
enum
{
// RCT2 categories (keep order)
SCENARIO_CATEGORY_BEGINNER,
SCENARIO_CATEGORY_CHALLENGING,
@@ -320,7 +328,8 @@ enum {
SCENARIO_CATEGORY_COUNT
};
enum {
enum
{
OBJECTIVE_NONE,
OBJECTIVE_GUESTS_BY,
OBJECTIVE_PARK_VALUE_BY,
@@ -335,12 +344,14 @@ enum {
OBJECTIVE_MONTHLY_FOOD_INCOME
};
enum {
enum
{
SCENARIO_SELECT_MODE_DIFFICULTY,
SCENARIO_SELECT_MODE_ORIGIN,
};
enum {
enum
{
AUTOSAVE_EVERY_MINUTE,
AUTOSAVE_EVERY_5MINUTES,
AUTOSAVE_EVERY_15MINUTES,
@@ -378,15 +389,15 @@ extern uint32_t gLastAutoSaveUpdate;
extern char gScenarioFileName[260];
void load_from_sc6(const char *path);
void load_from_sc6(const char* path);
void scenario_begin();
void scenario_update();
#ifdef DEBUG_DESYNC
uint32_t dbg_scenario_rand(const char *file, const char *function, const uint32_t line, const void *data);
uint32_t dbg_scenario_rand(const char* file, const char* function, const uint32_t line, const void* data);
#define scenario_rand() dbg_scenario_rand(__FILE__, __FUNCTION__, __LINE__, NULL)
#define scenario_rand_data(data) dbg_scenario_rand(__FILE__, __FUNCTION__, __LINE__, data)
void dbg_report_desync(uint32_t tick, uint32_t srand0, uint32_t server_srand0, const char *clientHash, const char *serverHash);
void dbg_report_desync(uint32_t tick, uint32_t srand0, uint32_t server_srand0, const char* clientHash, const char* serverHash);
#else
uint32_t scenario_rand();
#endif
@@ -394,12 +405,12 @@ uint32_t scenario_rand();
uint32_t scenario_rand_max(uint32_t max);
bool scenario_prepare_for_save();
int32_t scenario_save(const utf8 * path, int32_t flags);
void scenario_remove_trackless_rides(rct_s6_data *s6);
void scenario_fix_ghosts(rct_s6_data *s6);
int32_t scenario_save(const utf8* path, int32_t flags);
void scenario_remove_trackless_rides(rct_s6_data* s6);
void scenario_fix_ghosts(rct_s6_data* s6);
void scenario_failure();
void scenario_success();
void scenario_success_submit_name(const char *name);
void scenario_success_submit_name(const char* name);
void scenario_autosave_check();
#endif

View File

@@ -7,10 +7,13 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include <algorithm>
#include <memory>
#include <vector>
#include "ScenarioRepository.h"
#include "../Context.h"
#include "../Game.h"
#include "../ParkImporter.h"
#include "../PlatformEnvironment.h"
#include "../config/Config.h"
#include "../core/Console.hpp"
#include "../core/File.h"
#include "../core/FileIndex.hpp"
@@ -19,34 +22,36 @@
#include "../core/Path.hpp"
#include "../core/String.hpp"
#include "../core/Util.hpp"
#include "../ParkImporter.h"
#include "../PlatformEnvironment.h"
#include "../rct12/SawyerChunkReader.h"
#include "ScenarioRepository.h"
#include "ScenarioSources.h"
#include "../config/Config.h"
#include "../localisation/Language.h"
#include "../localisation/Localisation.h"
#include "../localisation/LocalisationService.h"
#include "../platform/platform.h"
#include "../rct12/SawyerChunkReader.h"
#include "Scenario.h"
#include "../Game.h"
#include "ScenarioSources.h"
#include <algorithm>
#include <memory>
#include <vector>
using namespace OpenRCT2;
static int32_t ScenarioCategoryCompare(int32_t categoryA, int32_t categoryB)
{
if (categoryA == categoryB) return 0;
if (categoryA == SCENARIO_CATEGORY_DLC) return -1;
if (categoryB == SCENARIO_CATEGORY_DLC) return 1;
if (categoryA == SCENARIO_CATEGORY_BUILD_YOUR_OWN) return -1;
if (categoryB == SCENARIO_CATEGORY_BUILD_YOUR_OWN) return 1;
if (categoryA == categoryB)
return 0;
if (categoryA == SCENARIO_CATEGORY_DLC)
return -1;
if (categoryB == SCENARIO_CATEGORY_DLC)
return 1;
if (categoryA == SCENARIO_CATEGORY_BUILD_YOUR_OWN)
return -1;
if (categoryB == SCENARIO_CATEGORY_BUILD_YOUR_OWN)
return 1;
return Math::Sign(categoryA - categoryB);
}
static int32_t scenario_index_entry_CompareByCategory(const scenario_index_entry &entryA,
const scenario_index_entry &entryB)
static int32_t scenario_index_entry_CompareByCategory(const scenario_index_entry& entryA, const scenario_index_entry& entryB)
{
// Order by category
if (entryA.category != entryB.category)
@@ -55,21 +60,21 @@ static int32_t scenario_index_entry_CompareByCategory(const scenario_index_entry
}
// Then by source game / name
switch (entryA.category) {
default:
if (entryA.source_game != entryB.source_game)
{
return entryA.source_game - entryB.source_game;
}
return strcmp(entryA.name, entryB.name);
case SCENARIO_CATEGORY_REAL:
case SCENARIO_CATEGORY_OTHER:
return strcmp(entryA.name, entryB.name);
switch (entryA.category)
{
default:
if (entryA.source_game != entryB.source_game)
{
return entryA.source_game - entryB.source_game;
}
return strcmp(entryA.name, entryB.name);
case SCENARIO_CATEGORY_REAL:
case SCENARIO_CATEGORY_OTHER:
return strcmp(entryA.name, entryB.name);
}
}
static int32_t scenario_index_entry_CompareByIndex(const scenario_index_entry &entryA,
const scenario_index_entry &entryB)
static int32_t scenario_index_entry_CompareByIndex(const scenario_index_entry& entryA, const scenario_index_entry& entryB)
{
// Order by source game
if (entryA.source_game != entryB.source_game)
@@ -79,37 +84,38 @@ static int32_t scenario_index_entry_CompareByIndex(const scenario_index_entry &e
// Then by index / category / name
uint8_t sourceGame = entryA.source_game;
switch (sourceGame) {
default:
if (entryA.source_index == -1 && entryB.source_index == -1)
{
if (entryA.category == entryB.category)
switch (sourceGame)
{
default:
if (entryA.source_index == -1 && entryB.source_index == -1)
{
return scenario_index_entry_CompareByCategory(entryA, entryB);
if (entryA.category == entryB.category)
{
return scenario_index_entry_CompareByCategory(entryA, entryB);
}
else
{
return ScenarioCategoryCompare(entryA.category, entryB.category);
}
}
else if (entryA.source_index == -1)
{
return 1;
}
else if (entryB.source_index == -1)
{
return -1;
}
else
{
return ScenarioCategoryCompare(entryA.category, entryB.category);
return entryA.source_index - entryB.source_index;
}
}
else if (entryA.source_index == -1)
{
return 1;
}
else if (entryB.source_index == -1)
{
return -1;
}
else
{
return entryA.source_index - entryB.source_index;
}
case SCENARIO_SOURCE_REAL:
return scenario_index_entry_CompareByCategory(entryA, entryB);
case SCENARIO_SOURCE_REAL:
return scenario_index_entry_CompareByCategory(entryA, entryB);
}
}
static void scenario_highscore_free(scenario_highscore_entry * highscore)
static void scenario_highscore_free(scenario_highscore_entry* highscore)
{
SafeFree(highscore->fileName);
SafeFree(highscore->name);
@@ -124,21 +130,21 @@ private:
static constexpr auto PATTERN = "*.sc4;*.sc6";
public:
explicit ScenarioFileIndex(const IPlatformEnvironment& env) :
FileIndex("scenario index",
MAGIC_NUMBER,
VERSION,
env.GetFilePath(PATHID::CACHE_SCENARIOS),
std::string(PATTERN),
std::vector<std::string>({
env.GetDirectoryPath(DIRBASE::RCT1, DIRID::SCENARIO),
env.GetDirectoryPath(DIRBASE::RCT2, DIRID::SCENARIO),
env.GetDirectoryPath(DIRBASE::USER, DIRID::SCENARIO) }))
explicit ScenarioFileIndex(const IPlatformEnvironment& env)
: FileIndex(
"scenario index",
MAGIC_NUMBER,
VERSION,
env.GetFilePath(PATHID::CACHE_SCENARIOS),
std::string(PATTERN),
std::vector<std::string>({ env.GetDirectoryPath(DIRBASE::RCT1, DIRID::SCENARIO),
env.GetDirectoryPath(DIRBASE::RCT2, DIRID::SCENARIO),
env.GetDirectoryPath(DIRBASE::USER, DIRID::SCENARIO) }))
{
}
protected:
std::tuple<bool, scenario_index_entry> Create(int32_t, const std::string &path) const override
std::tuple<bool, scenario_index_entry> Create(int32_t, const std::string& path) const override
{
scenario_index_entry entry;
auto timestamp = File::GetLastModified(path);
@@ -152,7 +158,7 @@ protected:
}
}
void Serialise(IStream * stream, const scenario_index_entry &item) const override
void Serialise(IStream* stream, const scenario_index_entry& item) const override
{
stream->Write(item.path, sizeof(item.path));
stream->WriteValue(item.timestamp);
@@ -172,7 +178,7 @@ protected:
stream->Write(item.details, sizeof(item.details));
}
scenario_index_entry Deserialise(IStream * stream) const override
scenario_index_entry Deserialise(IStream* stream) const override
{
scenario_index_entry item;
@@ -201,7 +207,7 @@ private:
/**
* Reads basic information from a scenario file.
*/
static bool GetScenarioInfo(const std::string &path, uint64_t timestamp, scenario_index_entry * entry)
static bool GetScenarioInfo(const std::string& path, uint64_t timestamp, scenario_index_entry* entry)
{
log_verbose("GetScenarioInfo(%s, %d, ...)", path.c_str(), timestamp);
try
@@ -222,7 +228,7 @@ private:
result = true;
}
}
catch (const std::exception &)
catch (const std::exception&)
{
}
return result;
@@ -248,14 +254,14 @@ private:
}
}
}
catch (const std::exception &)
catch (const std::exception&)
{
Console::Error::WriteLine("Unable to read scenario: '%s'", path.c_str());
}
return false;
}
static scenario_index_entry CreateNewScenarioEntry(const std::string &path, uint64_t timestamp, rct_s6_info * s6Info)
static scenario_index_entry CreateNewScenarioEntry(const std::string& path, uint64_t timestamp, rct_s6_info* s6Info)
{
scenario_index_entry entry = {};
@@ -280,8 +286,8 @@ private:
ScenarioSources::NormaliseName(entry.name, sizeof(entry.name), entry.name);
}
// entry.name will be translated later so keep the untranslated name here
String::Set(entry.internal_name, sizeof(entry.internal_name), entry.name);
// entry.name will be translated later so keep the untranslated name here
String::Set(entry.internal_name, sizeof(entry.internal_name), entry.name);
String::Set(entry.details, sizeof(entry.details), s6Info->details);
@@ -325,8 +331,8 @@ private:
public:
explicit ScenarioRepository(const std::shared_ptr<IPlatformEnvironment>& env)
: _env(env),
_fileIndex(*env)
: _env(env)
, _fileIndex(*env)
{
}
@@ -359,9 +365,9 @@ public:
return _scenarios.size();
}
const scenario_index_entry * GetByIndex(size_t index) const override
const scenario_index_entry* GetByIndex(size_t index) const override
{
const scenario_index_entry * result = nullptr;
const scenario_index_entry* result = nullptr;
if (index < _scenarios.size())
{
result = &_scenarios[index];
@@ -369,11 +375,11 @@ public:
return result;
}
const scenario_index_entry * GetByFilename(const utf8 * filename) const override
const scenario_index_entry* GetByFilename(const utf8* filename) const override
{
for (const auto &scenario : _scenarios)
for (const auto& scenario : _scenarios)
{
const utf8 * scenarioFilename = Path::GetFileName(scenario.path);
const utf8* scenarioFilename = Path::GetFileName(scenario.path);
// Note: this is always case insensitive search for cross platform consistency
if (String::Equals(filename, scenarioFilename, true))
@@ -384,24 +390,27 @@ public:
return nullptr;
}
const scenario_index_entry * GetByInternalName(const utf8 * name) const override {
for (size_t i = 0; i < _scenarios.size(); i++) {
const scenario_index_entry * scenario = &_scenarios[i];
if (scenario->source_game == SCENARIO_SOURCE_OTHER && scenario->sc_id == SC_UNIDENTIFIED)
continue;
// Note: this is always case insensitive search for cross platform consistency
if (String::Equals(name, scenario->internal_name, true)) {
return &_scenarios[i];
}
}
return nullptr;
}
const scenario_index_entry * GetByPath(const utf8 * path) const override
const scenario_index_entry* GetByInternalName(const utf8* name) const override
{
for (const auto &scenario : _scenarios)
for (size_t i = 0; i < _scenarios.size(); i++)
{
const scenario_index_entry* scenario = &_scenarios[i];
if (scenario->source_game == SCENARIO_SOURCE_OTHER && scenario->sc_id == SC_UNIDENTIFIED)
continue;
// Note: this is always case insensitive search for cross platform consistency
if (String::Equals(name, scenario->internal_name, true))
{
return &_scenarios[i];
}
}
return nullptr;
}
const scenario_index_entry* GetByPath(const utf8* path) const override
{
for (const auto& scenario : _scenarios)
{
if (Path::Equals(path, scenario.path))
{
@@ -411,19 +420,19 @@ public:
return nullptr;
}
bool TryRecordHighscore(int32_t language, const utf8 * scenarioFileName, money32 companyValue, const utf8 * name) override
bool TryRecordHighscore(int32_t language, const utf8* scenarioFileName, money32 companyValue, const utf8* name) override
{
// Scan the scenarios so we have a fresh list to query. This is to prevent the issue of scenario completions
// not getting recorded, see #4951.
Scan(language);
scenario_index_entry * scenario = GetByFilename(scenarioFileName);
scenario_index_entry* scenario = GetByFilename(scenarioFileName);
if (scenario != nullptr)
{
// Check if record company value has been broken or the highscore is the same but no name is registered
scenario_highscore_entry * highscore = scenario->highscore;
if (highscore == nullptr || companyValue > highscore->company_value ||
(String::IsNullOrEmpty(highscore->name) && companyValue == highscore->company_value))
scenario_highscore_entry* highscore = scenario->highscore;
if (highscore == nullptr || companyValue > highscore->company_value
|| (String::IsNullOrEmpty(highscore->name) && companyValue == highscore->company_value))
{
if (highscore == nullptr)
{
@@ -451,16 +460,16 @@ public:
}
private:
scenario_index_entry * GetByFilename(const utf8 * filename)
scenario_index_entry* GetByFilename(const utf8* filename)
{
const ScenarioRepository * repo = this;
return (scenario_index_entry *)repo->GetByFilename(filename);
const ScenarioRepository* repo = this;
return (scenario_index_entry*)repo->GetByFilename(filename);
}
scenario_index_entry * GetByPath(const utf8 * path)
scenario_index_entry* GetByPath(const utf8* path)
{
const ScenarioRepository * repo = this;
return (scenario_index_entry *)repo->GetByPath(path);
const ScenarioRepository* repo = this;
return (scenario_index_entry*)repo->GetByPath(path);
}
/**
@@ -483,7 +492,7 @@ private:
* @param srcPath Full path to mp.dat
* @param dstPath Full path to sc21.dat
*/
void ConvertMegaPark(const std::string &srcPath, const std::string &dstPath)
void ConvertMegaPark(const std::string& srcPath, const std::string& dstPath)
{
auto directory = Path::GetDirectory(dstPath);
platform_ensure_directory_exists(directory.c_str());
@@ -499,7 +508,7 @@ private:
File::WriteAllBytes(dstPath, mpdat.data(), mpdat.size());
}
void AddScenario(const scenario_index_entry &entry)
void AddScenario(const scenario_index_entry& entry)
{
auto filename = Path::GetFileName(entry.path);
@@ -539,19 +548,17 @@ private:
{
if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN)
{
std::sort(_scenarios.begin(), _scenarios.end(), [](const scenario_index_entry &a,
const scenario_index_entry &b) -> bool
{
return scenario_index_entry_CompareByIndex(a, b) < 0;
});
std::sort(
_scenarios.begin(), _scenarios.end(), [](const scenario_index_entry& a, const scenario_index_entry& b) -> bool {
return scenario_index_entry_CompareByIndex(a, b) < 0;
});
}
else
{
std::sort(_scenarios.begin(), _scenarios.end(), [](const scenario_index_entry &a,
const scenario_index_entry &b) -> bool
{
return scenario_index_entry_CompareByCategory(a, b) < 0;
});
std::sort(
_scenarios.begin(), _scenarios.end(), [](const scenario_index_entry& a, const scenario_index_entry& b) -> bool {
return scenario_index_entry_CompareByCategory(a, b) < 0;
});
}
}
@@ -578,14 +585,14 @@ private:
uint32_t numHighscores = fs.ReadValue<uint32_t>();
for (uint32_t i = 0; i < numHighscores; i++)
{
scenario_highscore_entry * highscore = InsertHighscore();
scenario_highscore_entry* highscore = InsertHighscore();
highscore->fileName = fs.ReadString();
highscore->name = fs.ReadString();
highscore->company_value = fs.ReadValue<money32>();
highscore->timestamp = fs.ReadValue<datetime64>();
}
}
catch (const std::exception &)
catch (const std::exception&)
{
Console::Error::WriteLine("Error reading highscores.");
}
@@ -603,7 +610,7 @@ private:
LoadLegacyScores(rct2Path);
}
void LoadLegacyScores(const std::string &path)
void LoadLegacyScores(const std::string& path)
{
if (!platform_file_exists(path.c_str()))
{
@@ -631,7 +638,7 @@ private:
if (scBasic.Flags & SCENARIO_FLAGS_COMPLETED)
{
bool notFound = true;
for (auto &highscore : _highscores)
for (auto& highscore : _highscores)
{
if (String::Equals(scBasic.Path, highscore->fileName, true))
{
@@ -651,7 +658,7 @@ private:
}
if (notFound)
{
scenario_highscore_entry * highscore = InsertHighscore();
scenario_highscore_entry* highscore = InsertHighscore();
highscore->fileName = String::Duplicate(scBasic.Path);
std::string name = rct2_to_utf8(scBasic.CompletedBy, RCT2_LANGUAGE_ID_ENGLISH_UK);
highscore->name = String::Duplicate(name.c_str());
@@ -661,7 +668,7 @@ private:
}
}
}
catch (const std::exception &)
catch (const std::exception&)
{
Console::Error::WriteLine("Error reading legacy scenario scores file: '%s'", path.c_str());
}
@@ -681,7 +688,7 @@ private:
_highscores.clear();
}
scenario_highscore_entry * InsertHighscore()
scenario_highscore_entry* InsertHighscore()
{
auto highscore = new scenario_highscore_entry();
memset(highscore, 0, sizeof(scenario_highscore_entry));
@@ -691,9 +698,9 @@ private:
void AttachHighscores()
{
for (auto &highscore : _highscores)
for (auto& highscore : _highscores)
{
scenario_index_entry * scenerio = GetByFilename(highscore->fileName);
scenario_index_entry* scenerio = GetByFilename(highscore->fileName);
if (scenerio != nullptr)
{
scenerio->highscore = highscore;
@@ -711,14 +718,14 @@ private:
fs.WriteValue<uint32_t>((uint32_t)_highscores.size());
for (size_t i = 0; i < _highscores.size(); i++)
{
const scenario_highscore_entry * highscore = _highscores[i];
const scenario_highscore_entry* highscore = _highscores[i];
fs.WriteString(highscore->fileName);
fs.WriteString(highscore->name);
fs.WriteValue(highscore->company_value);
fs.WriteValue(highscore->timestamp);
}
}
catch (const std::exception &)
catch (const std::exception&)
{
Console::Error::WriteLine("Unable to save highscores to '%s'", path.c_str());
}
@@ -730,32 +737,31 @@ std::unique_ptr<IScenarioRepository> CreateScenarioRepository(const std::shared_
return std::make_unique<ScenarioRepository>(env);
}
IScenarioRepository * GetScenarioRepository()
IScenarioRepository* GetScenarioRepository()
{
return GetContext()->GetScenarioRepository();
}
void scenario_repository_scan()
{
IScenarioRepository * repo = GetScenarioRepository();
IScenarioRepository* repo = GetScenarioRepository();
repo->Scan(LocalisationService_GetCurrentLanguage());
}
size_t scenario_repository_get_count()
{
IScenarioRepository * repo = GetScenarioRepository();
IScenarioRepository* repo = GetScenarioRepository();
return repo->GetCount();
}
const scenario_index_entry *scenario_repository_get_by_index(size_t index)
const scenario_index_entry* scenario_repository_get_by_index(size_t index)
{
IScenarioRepository * repo = GetScenarioRepository();
IScenarioRepository* repo = GetScenarioRepository();
return repo->GetByIndex(index);
}
bool scenario_repository_try_record_highscore(const utf8 * scenarioFileName, money32 companyValue, const utf8 * name)
bool scenario_repository_try_record_highscore(const utf8* scenarioFileName, money32 companyValue, const utf8* name)
{
IScenarioRepository * repo = GetScenarioRepository();
IScenarioRepository* repo = GetScenarioRepository();
return repo->TryRecordHighscore(LocalisationService_GetCurrentLanguage(), scenarioFileName, companyValue, name);
}

View File

@@ -9,37 +9,38 @@
#pragma once
#include <memory>
#include "../common.h"
#include <memory>
struct rct_object_entry;
struct scenario_highscore_entry
{
utf8 * fileName;
utf8 * name;
money32 company_value;
datetime64 timestamp;
utf8* fileName;
utf8* name;
money32 company_value;
datetime64 timestamp;
};
struct scenario_index_entry
{
utf8 path[MAX_PATH];
uint64_t timestamp;
utf8 path[MAX_PATH];
uint64_t timestamp;
// Category / sequence
uint8_t category;
uint8_t source_game;
int16_t source_index;
uint16_t sc_id;
uint8_t category;
uint8_t source_game;
int16_t source_index;
uint16_t sc_id;
// Objective
uint8_t objective_type;
uint8_t objective_arg_1;
int32_t objective_arg_2;
int16_t objective_arg_3;
scenario_highscore_entry * highscore;
uint8_t objective_type;
uint8_t objective_arg_1;
int32_t objective_arg_2;
int16_t objective_arg_3;
scenario_highscore_entry* highscore;
utf8 internal_name[64]; // Untranslated name
utf8 name[64]; // Translated name
utf8 details[256];
@@ -60,22 +61,23 @@ interface IScenarioRepository
virtual void Scan(int32_t language) abstract;
virtual size_t GetCount() const abstract;
virtual const scenario_index_entry * GetByIndex(size_t index) const abstract;
virtual const scenario_index_entry * GetByFilename(const utf8 * filename) const abstract;
/**
* Does not return custom scenarios due to the fact that they may have the same name.
*/
virtual const scenario_index_entry * GetByInternalName(const utf8 * name) const abstract;
virtual const scenario_index_entry * GetByPath(const utf8 * path) const abstract;
virtual const scenario_index_entry* GetByIndex(size_t index) const abstract;
virtual const scenario_index_entry* GetByFilename(const utf8* filename) const abstract;
/**
* Does not return custom scenarios due to the fact that they may have the same name.
*/
virtual const scenario_index_entry* GetByInternalName(const utf8* name) const abstract;
virtual const scenario_index_entry* GetByPath(const utf8* path) const abstract;
virtual bool TryRecordHighscore(int32_t language, const utf8 * scenarioFileName, money32 companyValue, const utf8 * name) abstract;
virtual bool TryRecordHighscore(int32_t language, const utf8* scenarioFileName, money32 companyValue, const utf8* name)
abstract;
};
std::unique_ptr<IScenarioRepository> CreateScenarioRepository(const std::shared_ptr<OpenRCT2::IPlatformEnvironment>& env);
IScenarioRepository * GetScenarioRepository();
IScenarioRepository* GetScenarioRepository();
void scenario_repository_scan();
size_t scenario_repository_get_count();
const scenario_index_entry *scenario_repository_get_by_index(size_t index);
bool scenario_repository_try_record_highscore(const utf8 * scenarioFileName, money32 companyValue, const utf8 * name);
void scenario_translate(scenario_index_entry * scenarioEntry, const struct rct_object_entry * stexObjectEntry);
void scenario_repository_scan();
size_t scenario_repository_get_count();
const scenario_index_entry* scenario_repository_get_by_index(size_t index);
bool scenario_repository_try_record_highscore(const utf8* scenarioFileName, money32 companyValue, const utf8* name);
void scenario_translate(scenario_index_entry* scenarioEntry, const struct rct_object_entry* stexObjectEntry);

View File

@@ -7,29 +7,29 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "ScenarioSources.h"
#include "../core/Guard.hpp"
#include "../core/String.hpp"
#include "../core/Util.hpp"
#include "ScenarioSources.h"
#include "Scenario.h"
namespace ScenarioSources
{
struct ScenarioAlias
{
const utf8 * Original;
const utf8 * Alternative;
const utf8* Original;
const utf8* Alternative;
};
struct ScenarioTitleDescriptor
{
const uint8_t Id;
const utf8 * Title;
const uint8_t Category;
const uint8_t Id;
const utf8* Title;
const uint8_t Category;
};
#pragma region Scenario Data
#pragma region Scenario Data
// clang-format off
static constexpr const ScenarioAlias ScenarioAliases[] =
@@ -316,9 +316,9 @@ namespace ScenarioSources
};
// clang-format on
#pragma endregion
#pragma endregion
bool TryGetByName(const utf8 * name, source_desc * outDesc)
bool TryGetByName(const utf8* name, source_desc* outDesc)
{
Guard::ArgumentNotNull(outDesc, GUARD_LINE);
@@ -327,7 +327,7 @@ namespace ScenarioSources
{
for (size_t j = 0; j < ScenarioTitlesBySource[i].count; j++)
{
const ScenarioTitleDescriptor *desc = &ScenarioTitlesBySource[i].titles[j];
const ScenarioTitleDescriptor* desc = &ScenarioTitlesBySource[i].titles[j];
if (String::Equals(name, desc->Title, true))
{
outDesc->title = desc->Title;
@@ -349,7 +349,7 @@ namespace ScenarioSources
return false;
}
bool TryGetById(uint8_t id, source_desc * outDesc)
bool TryGetById(uint8_t id, source_desc* outDesc)
{
Guard::ArgumentNotNull(outDesc, GUARD_LINE);
@@ -358,7 +358,7 @@ namespace ScenarioSources
{
for (size_t j = 0; j < ScenarioTitlesBySource[i].count; j++)
{
const ScenarioTitleDescriptor * desc = &ScenarioTitlesBySource[i].titles[j];
const ScenarioTitleDescriptor* desc = &ScenarioTitlesBySource[i].titles[j];
if (id == desc->Id)
{
outDesc->title = desc->Title;
@@ -380,7 +380,7 @@ namespace ScenarioSources
return false;
}
void NormaliseName(utf8 * buffer, size_t bufferSize, const utf8 * name)
void NormaliseName(utf8* buffer, size_t bufferSize, const utf8* name)
{
size_t nameLength = String::LengthOf(name);
@@ -403,7 +403,7 @@ namespace ScenarioSources
// American scenario titles should be converted to British name
// Don't worry, names will be translated using language packs later
for (const ScenarioAlias &alias : ScenarioAliases)
for (const ScenarioAlias& alias : ScenarioAliases)
{
if (String::Equals(alias.Alternative, name))
{
@@ -414,18 +414,17 @@ namespace ScenarioSources
}
} // namespace ScenarioSources
bool scenario_get_source_desc(const utf8 * name, source_desc * outDesc)
bool scenario_get_source_desc(const utf8* name, source_desc* outDesc)
{
return ScenarioSources::TryGetByName(name, outDesc);
}
bool scenario_get_source_desc_by_id(uint8_t id, source_desc * outDesc)
bool scenario_get_source_desc_by_id(uint8_t id, source_desc* outDesc)
{
return ScenarioSources::TryGetById(id, outDesc);
}
void scenario_normalise_name(utf8 * buffer, size_t bufferSize, utf8 * name)
void scenario_normalise_name(utf8* buffer, size_t bufferSize, utf8* name)
{
ScenarioSources::NormaliseName(buffer, bufferSize, name);
}

View File

@@ -13,24 +13,23 @@
struct source_desc
{
const utf8 * title;
uint8_t id;
uint8_t source;
int32_t index;
uint8_t category;
const utf8* title;
uint8_t id;
uint8_t source;
int32_t index;
uint8_t category;
};
namespace ScenarioSources
{
bool TryGetByName(const utf8 * name, source_desc * outDesc);
bool TryGetById(uint8_t id, source_desc * outDesc);
void NormaliseName(utf8 * buffer, size_t bufferSize, const utf8 * name);
}
bool scenario_get_source_desc(const utf8 *name, source_desc *outDesc);
bool scenario_get_source_desc_by_id(uint8_t id, source_desc *outDesc);
void scenario_normalise_name(utf8 *buffer, size_t bufferSize, utf8 *name);
bool TryGetByName(const utf8* name, source_desc* outDesc);
bool TryGetById(uint8_t id, source_desc* outDesc);
void NormaliseName(utf8* buffer, size_t bufferSize, const utf8* name);
} // namespace ScenarioSources
bool scenario_get_source_desc(const utf8* name, source_desc* outDesc);
bool scenario_get_source_desc_by_id(uint8_t id, source_desc* outDesc);
void scenario_normalise_name(utf8* buffer, size_t bufferSize, utf8* name);
// RCT1 scenario index map
enum