1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-22 06:23:04 +01:00

handle scenario conflicts

This commit is contained in:
IntelOrca
2015-12-31 21:13:49 +00:00
parent 8aa14f876e
commit 95ee0be3c5
5 changed files with 101 additions and 96 deletions

View File

@@ -438,7 +438,6 @@ void scenario_success()
} else {
scenario_highscore_free(scenario->highscore);
}
scenario->highscore->fileNameRoot = scenario->path_root;
scenario->highscore->fileName = (utf8*)path_get_filename(scenario->path);
scenario->highscore->name = NULL;
scenario->highscore->company_value = companyValue;

View File

@@ -421,18 +421,16 @@ enum {
};
typedef struct {
uint8 fileNameRoot;
utf8 *fileName;
utf8 *name;
money32 company_value;
} scenario_highscore_entry;
typedef struct {
uint8 path_root;
utf8 path[MAX_PATH];
uint64 timestamp;
// Category / sequence
uint8 flags;
uint8 category;
uint8 source_game;
sint16 source_index;
@@ -448,11 +446,6 @@ typedef struct {
utf8 details[256];
} scenario_index_entry;
enum {
SCENARIO_ROOT_RCT2,
SCENARIO_ROOT_USER,
};
// Scenario list
extern int gScenarioListCount;
extern int gScenarioListCapacity;
@@ -466,7 +459,6 @@ void scenario_load_list();
void scenario_list_dispose();
scenario_index_entry *scenario_list_find_by_filename(const utf8 *filename);
scenario_index_entry *scenario_list_find_by_path(const utf8 *path);
scenario_index_entry *scenario_list_find_by_root_path(uint8 root, const utf8 *filename);
scenario_highscore_entry *scenario_highscore_insert();
void scenario_highscore_free(scenario_highscore_entry *highscore);
int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info);

View File

@@ -33,14 +33,15 @@ int gScenarioHighscoreListCount = 0;
int gScenarioHighscoreListCapacity = 0;
scenario_highscore_entry *gScenarioHighscoreList = NULL;
static void scenario_list_include(uint8 pathRoot, const utf8 *directory);
static void scenario_list_add(uint8 pathRoot, const char *path);
static void scenario_list_include(const utf8 *directory);
static void scenario_list_add(const utf8 *path, uint64 timestamp);
static void scenario_list_sort();
static int scenario_list_sort_by_name(const void *a, const void *b);
static int scenario_list_sort_by_index(const void *a, const void *b);
static bool scenario_scores_load();
static bool scenario_scores_legacy_load();
static void scenario_scores_legacy_get_path(utf8 *outPath);
static bool scenario_scores_legacy_load(const utf8 *path);
static void scenario_highscore_remove(scenario_highscore_entry *higscore);
static void scenario_highscore_list_dispose();
static utf8 *io_read_string(SDL_RWops *file);
@@ -59,18 +60,23 @@ void scenario_load_list()
// Get scenario directory from RCT2
safe_strncpy(directory, gConfigGeneral.game_path, sizeof(directory));
safe_strcat_path(directory, "Scenarios", sizeof(directory));
scenario_list_include(SCENARIO_ROOT_RCT2, directory);
scenario_list_include(directory);
// Get scenario directory from user directory
platform_get_user_directory(directory, "scenario");
scenario_list_include(SCENARIO_ROOT_USER, directory);
scenario_list_include(directory);
scenario_list_sort();
scenario_scores_load();
scenario_scores_legacy_load();
utf8 scoresPath[MAX_PATH];
scenario_scores_legacy_get_path(scoresPath);
scenario_scores_legacy_load(scoresPath);
scenario_scores_legacy_load(get_file_path(PATH_ID_SCORES));
}
static void scenario_list_include(uint8 pathRoot, const utf8 *directory)
static void scenario_list_include(const utf8 *directory)
{
int handle;
file_info fileInfo;
@@ -85,7 +91,7 @@ static void scenario_list_include(uint8 pathRoot, const utf8 *directory)
utf8 path[MAX_PATH];
safe_strncpy(path, directory, sizeof(pattern));
safe_strcat_path(path, fileInfo.path, sizeof(pattern));
scenario_list_add(pathRoot, path);
scenario_list_add(path, fileInfo.last_modified);
}
platform_enumerate_files_end(handle);
@@ -96,12 +102,12 @@ static void scenario_list_include(uint8 pathRoot, const utf8 *directory)
utf8 path[MAX_PATH];
safe_strncpy(path, directory, sizeof(pattern));
safe_strcat_path(path, subDirectory, sizeof(pattern));
scenario_list_include(pathRoot, path);
scenario_list_include(path);
}
platform_enumerate_directories_end(handle);
}
static void scenario_list_add(uint8 pathRoot, const utf8 *path)
static void scenario_list_add(const utf8 *path, uint64 timestamp)
{
// Load the basic scenario information
rct_s6_header s6Header;
@@ -110,19 +116,44 @@ static void scenario_list_add(uint8 pathRoot, const utf8 *path)
return;
}
// Increase cache size
if (gScenarioListCount == gScenarioListCapacity) {
gScenarioListCapacity = max(8, gScenarioListCapacity * 2);
gScenarioList = (scenario_index_entry*)realloc(gScenarioList, gScenarioListCapacity * sizeof(scenario_index_entry));
scenario_index_entry *newEntry = NULL;
const utf8 *filename = path_get_filename(path);
scenario_index_entry *existingEntry = scenario_list_find_by_filename(filename);
if (existingEntry != NULL) {
bool bail = false;
const utf8 *conflictPath;
if (existingEntry->timestamp > timestamp) {
// Existing entry is more recent
conflictPath = existingEntry->path;
// Overwrite existing entry with this one
newEntry = existingEntry;
} else {
// This entry is more recent
conflictPath = path;
bail = true;
}
printf("Scenario conflict: '%s' ignored because it is newer.\n", conflictPath);
if (bail) {
return;
}
}
if (newEntry == NULL) {
// Increase list size
if (gScenarioListCount == gScenarioListCapacity) {
gScenarioListCapacity = max(8, gScenarioListCapacity * 2);
gScenarioList = (scenario_index_entry*)realloc(gScenarioList, gScenarioListCapacity * sizeof(scenario_index_entry));
}
newEntry = &gScenarioList[gScenarioListCount];
gScenarioListCount++;
}
scenario_index_entry *newEntry = &gScenarioList[gScenarioListCount];
gScenarioListCount++;
// Set new entry
newEntry->path_root = pathRoot;
safe_strncpy(newEntry->path, path, sizeof(newEntry->path));
newEntry->timestamp = timestamp;
newEntry->category = s6Info.category;
newEntry->flags = SCENARIO_FLAGS_VISIBLE;
newEntry->objective_type = s6Info.objective_type;
newEntry->objective_arg_1 = s6Info.objective_arg_1;
newEntry->objective_arg_2 = s6Info.objective_arg_2;
@@ -203,22 +234,6 @@ scenario_index_entry *scenario_list_find_by_path(const utf8 *path)
return NULL;
}
scenario_index_entry *scenario_list_find_by_root_path(uint8 root, const utf8 *filename)
{
// Derive path
utf8 path[MAX_PATH];
if (root == SCENARIO_ROOT_RCT2) {
safe_strncpy(path, gConfigGeneral.game_path, sizeof(path));
safe_strcat_path(path, "Scenarios", sizeof(path));
} else {
platform_get_user_directory(path, "scenario");
}
safe_strcat_path(path, filename, sizeof(path));
// Find matching scenario entry
return scenario_list_find_by_path(path);
}
/**
* Gets the path for the scenario scores path.
*/
@@ -241,18 +256,12 @@ static void scenario_scores_legacy_get_path(utf8 *outPath)
* Loads the original scores.dat file and replaces any highscores that
* are better for matching scenarios.
*/
static bool scenario_scores_legacy_load()
static bool scenario_scores_legacy_load(const utf8 *path)
{
utf8 scoresPath[MAX_PATH];
scenario_scores_legacy_get_path(scoresPath);
// First check user folder and then fallback to install directory
SDL_RWops *file = SDL_RWFromFile(scoresPath, "rb");
SDL_RWops *file = SDL_RWFromFile(path, "rb");
if (file == NULL) {
file = SDL_RWFromFile(get_file_path(PATH_ID_SCORES), "rb");
if (file == NULL) {
return false;
}
return false;
}
// Load header
@@ -278,7 +287,7 @@ static bool scenario_scores_legacy_load()
}
// Find matching scenario entry
scenario_index_entry *scenarioIndexEntry = scenario_list_find_by_root_path(SCENARIO_ROOT_RCT2, scBasic.path);
scenario_index_entry *scenarioIndexEntry = scenario_list_find_by_filename(scBasic.path);
if (scenarioIndexEntry != NULL) {
// Check if legacy highscore is better
scenario_highscore_entry *highscore = scenarioIndexEntry->highscore;
@@ -294,7 +303,6 @@ static bool scenario_scores_legacy_load()
// Set new highscore
if (highscore != NULL) {
highscore->fileNameRoot = SCENARIO_ROOT_RCT2;
highscore->fileName = _strdup(scBasic.path);
highscore->name = _strdup(scBasic.completed_by);
highscore->company_value = (money32)scBasic.company_value;
@@ -341,8 +349,6 @@ static bool scenario_scores_load()
// Read highscores
for (int i = 0; i < gScenarioHighscoreListCount; i++) {
scenario_highscore_entry *highscore = &gScenarioHighscoreList[i];
SDL_RWread(file, &highscore->fileNameRoot, sizeof(highscore->fileNameRoot), 1);
highscore->fileName = io_read_string(file);
highscore->name = io_read_string(file);
SDL_RWread(file, &highscore->company_value, sizeof(highscore->company_value), 1);
@@ -379,7 +385,6 @@ bool scenario_scores_save()
SDL_RWwrite(file, &gScenarioHighscoreListCount, sizeof(gScenarioHighscoreListCount), 1);
for (int i = 0; i < gScenarioHighscoreListCount; i++) {
scenario_highscore_entry *highscore = &gScenarioHighscoreList[i];
SDL_RWwrite(file, &highscore->fileNameRoot, sizeof(highscore->fileNameRoot), 1);
io_write_string(file, highscore->fileName);
io_write_string(file, highscore->name);
SDL_RWwrite(file, &highscore->company_value, sizeof(highscore->company_value), 1);

View File

@@ -664,8 +664,7 @@ static void window_options_mouseup(rct_window *w, int widgetIndex)
case WIDX_DEBUGGING_TOOLS:
gConfigGeneral.debugging_tools ^= 1;
config_save_default();
window_invalidate(w);
window_invalidate_by_class(WC_TOP_TOOLBAR);
gfx_invalidate_screen();
break;
case WIDX_TEST_UNFINISHED_TRACKS:
gConfigGeneral.test_unfinished_tracks ^= 1;

View File

@@ -187,14 +187,12 @@ static void window_scenarioselect_init_tabs()
int show_pages = 0;
for (int i = 0; i < gScenarioListCount; i++) {
scenario_index_entry *scenario = &gScenarioList[i];
if (scenario->flags & SCENARIO_FLAGS_VISIBLE) {
if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN) {
show_pages |= 1 << scenario->source_game;
} else {
show_pages |= 1 << scenario->category;
}
}
}
int x = 3;
for (int i = 0; i < 8; i++) {
@@ -220,7 +218,7 @@ static void window_scenarioselect_mouseup(rct_window *w, int widgetIndex)
{
if (widgetIndex == WIDX_CLOSE) {
window_close(w);
}
}
}
static void window_scenarioselect_mousedown(int widgetIndex, rct_window*w, rct_widget* widget)
@@ -263,18 +261,18 @@ static void window_scenarioselect_scrollmousedown(rct_window *w, int scrollIndex
switch (listItem->type) {
case LIST_ITEM_TYPE_HEADING:
y -= 18;
break;
break;
case LIST_ITEM_TYPE_SCENARIO:
y -= 24;
y -= 24;
if (y < 0 && !listItem->scenario.is_locked) {
audio_play_sound_panned(SOUND_CLICK_1, w->width / 2 + w->x, 0, 0, 0);
audio_play_sound_panned(SOUND_CLICK_1, w->width / 2 + w->x, 0, 0, 0);
scenario_load_and_play_from_path(listItem->scenario.scenario->path);
}
break;
}
break;
}
if (y < 0) {
break;
}
}
}
}
@@ -295,11 +293,11 @@ static void window_scenarioselect_scrollmouseover(rct_window *w, int scrollIndex
if (y < 0 && !listItem->scenario.is_locked) {
selected = listItem->scenario.scenario;
}
break;
break;
}
if (y < 0) {
break;
}
break;
}
}
if (w->highlighted_item != (uint32)selected) {
@@ -329,7 +327,9 @@ static void window_scenarioselect_invalidate(rct_window *w)
int windowHeight = w->height;
window_scenarioselect_widgets[WIDX_BACKGROUND].bottom = windowHeight - 1;
window_scenarioselect_widgets[WIDX_TABCONTENT].bottom = windowHeight - 1;
window_scenarioselect_widgets[WIDX_SCENARIOLIST].bottom = windowHeight - 5;
const int bottomMargin = gConfigGeneral.debugging_tools ? 17 : 5;
window_scenarioselect_widgets[WIDX_SCENARIOLIST].bottom = windowHeight - bottomMargin;
}
static void window_scenarioselect_paint(rct_window *w, rct_drawpixelinfo *dpi)
@@ -364,6 +364,12 @@ static void window_scenarioselect_paint(rct_window *w, rct_drawpixelinfo *dpi)
if (scenario == NULL)
return;
// Scenario path
if (gConfigGeneral.debugging_tools) {
const utf8 *path = scenario->path;
gfx_draw_string_left(dpi, 1170, (void*)&path, w->colours[1], w->x + 3, w->y + w->height - 3 - 11);
}
// Scenario name
x = w->x + window_scenarioselect_widgets[WIDX_SCENARIOLIST].right + 4;
y = w->y + window_scenarioselect_widgets[WIDX_TABCONTENT].top + 5;
@@ -386,7 +392,11 @@ static void window_scenarioselect_paint(rct_window *w, rct_drawpixelinfo *dpi)
// Scenario score
if (scenario->highscore != NULL) {
safe_strncpy((char*)0x009BC677, scenario->highscore->name, 64);
const utf8 *completedByName = "???";
if (!str_is_null_or_empty(scenario->highscore->name)) {
completedByName = scenario->highscore->name;
}
safe_strncpy((char*)0x009BC677, completedByName, 64);
RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, short) = 3165; // empty string
RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, int) = scenario->highscore->company_value;
y += gfx_draw_string_left_wrapped(dpi, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, x, y, 170, STR_COMPLETED_BY_WITH_COMPANY_VALUE, 0);
@@ -421,36 +431,40 @@ static void window_scenarioselect_scrollpaint(rct_window *w, rct_drawpixelinfo *
y += 18;
break;
case LIST_ITEM_TYPE_SCENARIO:;
// Draw hover highlight
// Draw hover highlight
scenario_index_entry *scenario = listItem->scenario.scenario;
bool isHighlighted = w->highlighted_item == (uint32)scenario;
if (isHighlighted) {
gfx_fill_rect(dpi, 0, y, w->width, y + 23, 0x02000031);
}
gfx_fill_rect(dpi, 0, y, w->width, y + 23, 0x02000031);
}
bool isCompleted = scenario->highscore != NULL;
bool isDisabled = listItem->scenario.is_locked;
// Draw scenario name
rct_string_id placeholderStringId = 3165;
safe_strncpy((char*)language_get_string(placeholderStringId), scenario->name, 64);
// Draw scenario name
rct_string_id placeholderStringId = 3165;
safe_strncpy((char*)language_get_string(placeholderStringId), scenario->name, 64);
int format = isDisabled ? 865 : (isHighlighted ? highlighted_format : unhighlighted_format);
colour = isDisabled ? w->colours[1] | 0x40 : COLOUR_BLACK;
gfx_draw_string_centred(dpi, format, wide ? 270 : 210, y + 1, colour, &placeholderStringId);
gfx_draw_string_centred(dpi, format, wide ? 270 : 210, y + 1, colour, &placeholderStringId);
// Check if scenario is completed
// Check if scenario is completed
if (isCompleted) {
// Draw completion tick
gfx_draw_sprite(dpi, 0x5A9F, wide ? 500 : 395, y + 1, 0);
// Draw completion tick
gfx_draw_sprite(dpi, 0x5A9F, wide ? 500 : 395, y + 1, 0);
// Draw completion score
safe_strncpy((char*)language_get_string(placeholderStringId), scenario->highscore->name, 64);
RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, rct_string_id) = 2793;
RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, rct_string_id) = placeholderStringId;
gfx_draw_string_centred(dpi, format, wide ? 270 : 210, y + 11, 0, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS);
}
// Draw completion score
const utf8 *completedByName = "???";
if (!str_is_null_or_empty(scenario->highscore->name)) {
completedByName = scenario->highscore->name;
}
safe_strncpy((char*)language_get_string(placeholderStringId), completedByName, 64);
RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, rct_string_id) = 2793;
RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, rct_string_id) = placeholderStringId;
gfx_draw_string_centred(dpi, format, wide ? 270 : 210, y + 11, 0, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS);
}
y += 24;
y += 24;
break;
}
}
@@ -482,7 +496,7 @@ static void draw_category_heading(rct_window *w, rct_drawpixelinfo *dpi, int lef
lineY++;
gfx_draw_line(dpi, left, lineY, strLeft, lineY, darkColour);
gfx_draw_line(dpi, strRight, lineY, right, lineY, darkColour);
}
}
static void initialise_list_items(rct_window *w)
{
@@ -560,10 +574,6 @@ static bool is_scenario_visible(rct_window *w, scenario_index_entry *scenario)
return false;
}
if (!(scenario->flags & SCENARIO_FLAGS_VISIBLE)) {
return false;
}
return true;
}