OpenRCT2/src/scenario_list.c

245 lines
6.8 KiB
C

/*****************************************************************************
* Copyright (c) 2014 Ted John
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* This file is part of OpenRCT2.
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "addresses.h"
#include "platform/platform.h"
#include "scenario.h"
// Scenario list
int gScenarioListCount = 0;
int gScenarioListCapacity = 0;
rct_scenario_basic *gScenarioList = NULL;
static void scenario_list_add(const char *path);
static void scenario_list_sort();
static int scenario_list_sort_compare(const void *a, const void *b);
static int scenario_scores_load();
rct_scenario_basic *get_scenario_by_filename(const char *filename)
{
int i;
for (i = 0; i < gScenarioListCount; i++)
if (strcmp(gScenarioList[i].path, filename) == 0)
return &gScenarioList[i];
return NULL;
}
/**
*
* rct2: 0x006775A8
*/
void scenario_load_list()
{
int i, enumFileHandle;
file_info enumFileInfo;
// Load scores
scenario_scores_load();
// Set all scenarios to be invisible
for (i = 0; i < gScenarioListCount; i++)
gScenarioList[i].flags &= ~SCENARIO_FLAGS_VISIBLE;
// Enumerate through each scenario in the directory
enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char));
if (enumFileHandle != INVALID_HANDLE) {
while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) {
scenario_list_add(enumFileInfo.path);
}
platform_enumerate_files_end(enumFileHandle);
}
// Sort alphabetically
scenario_list_sort();
// Save the scores
scenario_scores_save();
}
static void scenario_list_add(const char *path)
{
char scenarioPath[MAX_PATH];
rct_scenario_basic *scenario;
rct_s6_header s6Header;
rct_s6_info s6Info;
// Get absolute path
subsitute_path(scenarioPath, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), path);
// Load the basic scenario information
if (!scenario_load_basic(scenarioPath, &s6Header, &s6Info))
return;
// Ignore scenarios where first header byte is not 255
if (s6Info.editor_step != 255)
return;
// Check if scenario already exists in list, likely if in scores
scenario = get_scenario_by_filename(path);
if (scenario != NULL) {
// Update the scenario information
scenario->flags |= SCENARIO_FLAGS_VISIBLE;
scenario->category = s6Info.category;
scenario->objective_type = s6Info.objective_type;
scenario->objective_arg_1 = s6Info.objective_arg_1;
scenario->objective_arg_2 = s6Info.objective_arg_2;
scenario->objective_arg_3 = s6Info.objective_arg_3;
strcpy(scenario->name, s6Info.name);
strcpy(scenario->details, s6Info.details);
} else {
// Check if the scenario list buffer has room for another scenario
if (gScenarioListCount >= gScenarioListCapacity) {
// Allocate more room
gScenarioListCapacity += 16;
gScenarioList = realloc(gScenarioList, gScenarioListCapacity * sizeof(rct_scenario_basic));
}
// Increment the number of scenarios
scenario = &gScenarioList[gScenarioListCount];
gScenarioListCount++;
// Add this new scenario to the list
strcpy(scenario->path, path);
scenario->flags = SCENARIO_FLAGS_VISIBLE;
if (RCT2_GLOBAL(0x009AA00C, uint8) & 1)
scenario->flags |= SCENARIO_FLAGS_SIXFLAGS;
scenario->category = s6Info.category;
scenario->objective_type = s6Info.objective_type;
scenario->objective_arg_1 = s6Info.objective_arg_1;
scenario->objective_arg_2 = s6Info.objective_arg_2;
scenario->objective_arg_3 = s6Info.objective_arg_3;
strcpy(scenario->name, s6Info.name);
strcpy(scenario->details, s6Info.details);
}
}
/**
* Sort the list of scenarios. This used to be an insertion sort which took
* place as each scenario loaded. It has now been changed to a quicksort which
* takes place after all the scenarios have been loaded in.
* rct2: 0x00677C3B
*/
static void scenario_list_sort()
{
qsort(gScenarioList, gScenarioListCount, sizeof(rct_scenario_basic), scenario_list_sort_compare);
}
/**
* Basic scenario information compare function for sorting.
* rct2: 0x00677C08
*/
static int scenario_list_sort_compare(const void *a, const void *b)
{
return strcmp(((rct_scenario_basic*)a)->name, ((rct_scenario_basic*)b)->name);
}
/**
* Gets the path for the scenario scores path.
*/
static void scenario_scores_get_path(utf8 *outPath)
{
platform_get_user_directory(outPath, NULL);
strcat(outPath, "scores.dat");
}
/**
*
* rct2: 0x006775A8
*/
static int scenario_scores_load()
{
SDL_RWops *file;
char scoresPath[MAX_PATH];
scenario_scores_get_path(scoresPath);
// Free scenario list if already allocated
if (gScenarioList != NULL) {
free(gScenarioList);
gScenarioList = NULL;
}
// Try and load the scores file
// First check user folder and then fallback to install directory
file = SDL_RWFromFile(scoresPath, "rb");
if (file == NULL) {
file = SDL_RWFromFile(get_file_path(PATH_ID_SCORES), "rb");
if (file == NULL) {
log_error("Unable to load scenario scores.");
return 0;
}
}
// Load header
rct_scenario_scores_header header;
if (SDL_RWread(file, &header, 16, 1) != 1) {
SDL_RWclose(file);
log_error("Invalid header in scenario scores file.");
return 0;
}
gScenarioListCount = header.scenario_count;
// Load scenario information with scores
int scenarioListBufferSize = gScenarioListCount * sizeof(rct_scenario_basic);
gScenarioListCapacity = gScenarioListCount;
gScenarioList = malloc(scenarioListBufferSize);
if (SDL_RWread(file, gScenarioList, scenarioListBufferSize, 1) == 1) {
SDL_RWclose(file);
return 1;
}
// Unable to load scores, free scenario list
SDL_RWclose(file);
gScenarioListCount = 0;
gScenarioListCapacity = 0;
free(gScenarioList);
gScenarioList = NULL;
return 0;
}
/**
*
* rct2: 0x00677B50
*/
int scenario_scores_save()
{
SDL_RWops *file;
utf8 scoresPath[MAX_PATH];
scenario_scores_get_path(scoresPath);
file = SDL_RWFromFile(scoresPath, "wb");
if (file == NULL) {
log_error("Unable to save scenario scores.");
return 0;
}
rct_scenario_scores_header header;
header.scenario_count = gScenarioListCount;
SDL_RWwrite(file, &header, sizeof(header), 1);
if (gScenarioListCount > 0)
SDL_RWwrite(file, gScenarioList, gScenarioListCount * sizeof(rct_scenario_basic), 1);
SDL_RWclose(file);
return 1;
}