mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-04 13:42:55 +01:00
clang-format scenario
This commit is contained in:
committed by
Hielke Morsink
parent
e8310d079d
commit
861715a169
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user