OpenRCT2/src/rct2.c

497 lines
12 KiB
C

#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/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.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#pragma warning(disable : 4996) // GetVersionExA deprecated
#include <time.h>
#include "audio/audio.h"
#include "audio/mixer.h"
#include "config.h"
#include "drawing/drawing.h"
#include "editor.h"
#include "game.h"
#include "input.h"
#include "interface/chat.h"
#include "interface/console.h"
#include "interface/viewport.h"
#include "intro.h"
#include "localisation/date.h"
#include "localisation/localisation.h"
#include "management/news_item.h"
#include "network/network.h"
#include "network/twitch.h"
#include "object.h"
#include "object/ObjectManager.h"
#include "openrct2.h"
#include "peep/staff.h"
#include "platform/platform.h"
#include "rct1.h"
#include "ride/ride.h"
#include "ride/track.h"
#include "ride/track_design.h"
#include "scenario.h"
#include "title.h"
#include "util/util.h"
#include "world/map.h"
#include "world/park.h"
#include "world/climate.h"
#include "world/scenery.h"
#include "world/sprite.h"
// rct2: 0x0097F67C
const char * const RCT2FilePaths[PATH_ID_END] = {
"Data" PATH_SEPARATOR "g1.dat",
"Data" PATH_SEPARATOR "plugin.dat",
"Data" PATH_SEPARATOR "css1.dat",
"Data" PATH_SEPARATOR "css2.dat",
"Data" PATH_SEPARATOR "css4.dat",
"Data" PATH_SEPARATOR "css5.dat",
"Data" PATH_SEPARATOR "css6.dat",
"Data" PATH_SEPARATOR "css7.dat",
"Data" PATH_SEPARATOR "css8.dat",
"Data" PATH_SEPARATOR "css9.dat",
"Data" PATH_SEPARATOR "css11.dat",
"Data" PATH_SEPARATOR "css12.dat",
"Data" PATH_SEPARATOR "css13.dat",
"Data" PATH_SEPARATOR "css14.dat",
"Data" PATH_SEPARATOR "css15.dat",
"Data" PATH_SEPARATOR "css3.dat",
"Data" PATH_SEPARATOR "css17.dat",
"Data" PATH_SEPARATOR "css18.dat",
"Data" PATH_SEPARATOR "css19.dat",
"Data" PATH_SEPARATOR "css20.dat",
"Data" PATH_SEPARATOR "css21.dat",
"Data" PATH_SEPARATOR "css22.dat",
"Saved Games" PATH_SEPARATOR "scores.dat",
"Data" PATH_SEPARATOR "css23.dat",
"Data" PATH_SEPARATOR "css24.dat",
"Data" PATH_SEPARATOR "css25.dat",
"Data" PATH_SEPARATOR "css26.dat",
"Data" PATH_SEPARATOR "css27.dat",
"Data" PATH_SEPARATOR "css28.dat",
"Data" PATH_SEPARATOR "css29.dat",
"Data" PATH_SEPARATOR "css30.dat",
"Data" PATH_SEPARATOR "css31.dat",
"Data" PATH_SEPARATOR "css32.dat",
"Data" PATH_SEPARATOR "css33.dat",
"Data" PATH_SEPARATOR "css34.dat",
"Data" PATH_SEPARATOR "css35.dat",
"Data" PATH_SEPARATOR "css36.dat",
"Data" PATH_SEPARATOR "css37.dat",
"Data" PATH_SEPARATOR "css38.dat",
"Data" PATH_SEPARATOR "CUSTOM1.WAV",
"Data" PATH_SEPARATOR "CUSTOM2.WAV",
"Data" PATH_SEPARATOR "css39.dat",
"Data" PATH_SEPARATOR "css40.dat",
"Data" PATH_SEPARATOR "css41.dat",
"Scenarios" PATH_SEPARATOR "Six Flags Magic Mountain.SC6",
"Data" PATH_SEPARATOR "css42.dat",
"Data" PATH_SEPARATOR "css43.dat",
"Data" PATH_SEPARATOR "css44.dat",
"Data" PATH_SEPARATOR "css45.dat",
"Data" PATH_SEPARATOR "css46.dat",
"Data" PATH_SEPARATOR "css50.dat"
};
uint32 gCurrentDrawCount = 0;
uint8 gScreenFlags;
uint32 gScreenAge;
uint8 gSavePromptMode;
sint32 gScreenWidth;
sint32 gScreenHeight;
char gRCT2AddressAppPath[MAX_PATH];
char gRCT2AddressSavedGamesPath[MAX_PATH];
char gRCT2AddressSavedGamesPath2[MAX_PATH];
char gRCT2AddressScenariosPath[MAX_PATH];
char gRCT2AddressLandscapesPath[MAX_PATH];
char gRCT2AddressObjectDataPath[MAX_PATH];
char gRCT2AddressTracksPath[MAX_PATH];
typedef struct tm tm_t;
void print_launch_information();
int rct2_init_directories();
int rct2_startup_checks();
static void rct2_draw_fps(rct_drawpixelinfo *dpi);
void rct2_quit()
{
gSavePromptMode = PM_QUIT;
window_save_prompt_open();
}
void rct2_dispose()
{
object_manager_unload_all_objects();
gfx_unload_g2();
gfx_unload_g1();
}
bool rct2_init()
{
log_verbose("initialising game");
gScenarioTicks = 0;
util_srand((unsigned int)time(0));
if (!rct2_init_directories())
return false;
if (!rct2_startup_checks())
return false;
config_reset_shortcut_keys();
config_shortcut_keys_load();
gInputPlaceObjectModifier = PLACE_OBJECT_MODIFIER_NONE;
// config_load();
if (!gfx_load_g1()) {
return false;
}
if (!gfx_load_g2()) {
return false;
}
object_list_load();
scenario_load_list();
track_design_index_create();
font_sprite_initialise_characters();
if (!gOpenRCT2Headless) {
platform_init();
audio_init_ride_sounds_and_info();
}
viewport_init_all();
news_item_init_queue();
reset_park_entrances();
user_string_clear_all();
reset_sprite_list();
ride_init_all();
window_guest_list_init_vars_a();
staff_reset_modes();
map_init(150);
park_init();
if (!gOpenRCT2Headless)
window_title_menu_open();
date_reset();
climate_reset(CLIMATE_COOL_AND_WET);
scenery_set_default_placement_configuration();
window_new_ride_init_vars();
window_guest_list_init_vars_b();
window_staff_list_init_vars();
if (!gOpenRCT2Headless) {
title_load();
}
log_verbose("initialising game finished");
return true;
}
/**
*
* rct2: 0x00683499
*/
int rct2_init_directories()
{
// windows_get_registry_install_info((rct2_install_info*)0x009AA10C, "RollerCoaster Tycoon 2 Setup", "MS Sans Serif", 0);
char separator[] = {platform_get_path_separator(), 0};
if (str_is_null_or_empty(gCustomRCT2DataPath)) {
// check install directory
if (!platform_original_game_data_exists(gConfigGeneral.game_path)) {
log_verbose("install directory does not exist or invalid directory selected, %s", gConfigGeneral.game_path);
if (!config_find_or_browse_install_directory()) {
utf8 path[MAX_PATH];
config_get_default_path(path);
log_fatal("Invalid RCT2 installation path. Please correct \"game_path\" in %s.", path);
return 0;
}
}
strcpy(gRCT2AddressAppPath, gConfigGeneral.game_path);
} else {
strcpy(gRCT2AddressAppPath, gCustomRCT2DataPath);
}
strcat(gRCT2AddressAppPath, separator);
strcpy(gRCT2AddressSavedGamesPath, gRCT2AddressAppPath);
strcat(gRCT2AddressSavedGamesPath, "Saved Games");
strcat(gRCT2AddressSavedGamesPath, separator);
strcpy(gRCT2AddressScenariosPath, gRCT2AddressAppPath);
strcat(gRCT2AddressScenariosPath, "Scenarios");
strcat(gRCT2AddressScenariosPath, separator);
strcat(gRCT2AddressScenariosPath, "*.SC6");
strcpy(gRCT2AddressLandscapesPath, gRCT2AddressAppPath);
strcat(gRCT2AddressLandscapesPath, "Landscapes");
strcat(gRCT2AddressLandscapesPath, separator);
strcat(gRCT2AddressLandscapesPath, "*.SC6");
strcpy(gRCT2AddressObjectDataPath, gRCT2AddressAppPath);
strcat(gRCT2AddressObjectDataPath, "ObjData");
strcat(gRCT2AddressObjectDataPath, separator);
strcat(gRCT2AddressObjectDataPath, "*.DAT");
strcpy(gRCT2AddressTracksPath, gRCT2AddressAppPath);
strcat(gRCT2AddressTracksPath, "Tracks");
strcat(gRCT2AddressTracksPath, separator);
strcat(gRCT2AddressTracksPath, "*.TD?");
strcpy(gRCT2AddressSavedGamesPath2, gRCT2AddressSavedGamesPath);
return 1;
}
void substitute_path(char *dest, const char *path, const char *filename)
{
while (*path != '*') {
*dest++ = *path++;
}
strcpy(dest, filename);
}
/**
*
* rct2: 0x00674B42
*/
int rct2_startup_checks()
{
if (!check_file_paths())
return 0;
return 1;
}
void rct2_draw(rct_drawpixelinfo *dpi)
{
if (gIntroState != INTRO_STATE_NONE) {
return;
}
// redraw_rain();
// window_update_all();
// gfx_invalidate_pickedup_peep();
// gfx_draw_pickedup_peep();
// update_rain_animation();
update_palette_effects();
chat_draw(dpi);
console_draw(dpi);
if (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) {
DrawOpenRCT2(dpi, 0, gScreenHeight - 20);
}
if (gConfigGeneral.show_fps) {
rct2_draw_fps(dpi);
}
gCurrentDrawCount++;
}
static time_t _lastSecond;
static int _currentFPS;
static int _frames;
static void rct2_measure_fps()
{
_frames++;
time_t currentTime = time(NULL);
if (currentTime != _lastSecond) {
_currentFPS = _frames;
_frames = 0;
}
_lastSecond = currentTime;
}
static void rct2_draw_fps(rct_drawpixelinfo *dpi)
{
int x = gScreenWidth / 2;
int y = 2;
// Measure FPS
rct2_measure_fps();
// Format string
utf8 buffer[64];
utf8 *ch = buffer;
ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT);
ch = utf8_write_codepoint(ch, FORMAT_OUTLINE);
ch = utf8_write_codepoint(ch, FORMAT_WHITE);
sprintf(ch, "%d", _currentFPS);
// Draw Text
int stringWidth = gfx_get_string_width(buffer);
x = x - (stringWidth / 2);
gfx_draw_string(dpi, buffer, 0, x, y);
// Make area dirty so the text doesn't get drawn over the last
gfx_set_dirty_blocks(x - 16, y - 4, gLastDrawStringX + 16, 16);
}
bool rct2_open_file(const char *path)
{
char *extension = strrchr(path, '.');
if (extension == NULL) {
return false;
}
extension++;
if (_stricmp(extension, "sv6") == 0) {
strcpy((char*)gRCT2AddressSavedGamesPath2, path);
game_load_save(path);
gFirstTimeSave = 0;
return true;
} else if (_stricmp(extension, "sc6") == 0) {
// TODO scenario install
rct_scenario_basic scenarioBasic;
strcpy(scenarioBasic.path, path);
scenario_load_and_play_from_path(scenarioBasic.path);
return true;
} else if (_stricmp(extension, "td6") == 0 || _stricmp(extension, "td4") == 0) {
// TODO track design install
return true;
} else if (_stricmp(extension, "sv4") == 0) {
if (rct1_load_saved_game(path)) {
game_load_init();
}
} else if (_stricmp(extension, "sc4") == 0) {
if (rct1_load_scenario(path)) {
scenario_begin();
}
}
return false;
}
/**
*
* rct2: 0x00674C95
*/
int check_file_paths()
{
for (int pathId = 0; pathId < PATH_ID_END; pathId++) {
if (!check_file_path(pathId)) {
return 0;
}
}
return 1;
}
/**
*
* rct2: 0x00674CA5
*/
int check_file_path(int pathId)
{
const utf8* path = get_file_path(pathId);
SDL_RWops *file = SDL_RWFromFile(path, "rb");
switch (pathId) {
case PATH_ID_G1:
if (file == NULL) {
log_fatal("Could not find file %s", path);
return 0;
}
break;
case PATH_ID_CUSTOM1:
if (file != NULL) {
// Store file size in music_custom1_size @ 0x009AF164
gRideMusicInfoList[36]->length = (uint32)SDL_RWsize(file);
}
break;
case PATH_ID_CUSTOM2:
if (file != NULL) {
// Store file size in music_custom2_size @ 0x009AF16E
gRideMusicInfoList[37]->length = (uint32)SDL_RWsize(file);
}
break;
}
if (file != NULL) {
SDL_RWclose(file);
}
return 1;
}
void rct2_update()
{
int tickCount = SDL_GetTicks();
gTicksSinceLastUpdate = min(tickCount - gLastTickCount, 500);
gLastTickCount = tickCount;
if (game_is_not_paused()) {
gPaletteEffectFrame += gTicksSinceLastUpdate;
}
date_update_real_time_of_day();
// TODO: screenshot countdown process
network_update();
// check_cmdline_arg();
// Screens
if (gIntroState != INTRO_STATE_NONE) {
intro_update();
} else if ((gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) && !gOpenRCT2Headless) {
title_update();
} else {
game_update();
}
//stop_completed_sounds(); // removes other sounds that are no longer playing in directsound
twitch_update();
chat_update();
console_update();
}
/**
*
* rct2: 0x00674E6C
*/
const utf8 *get_file_path(int pathId)
{
static utf8 path[MAX_PATH];
strcpy(path, gRCT2AddressAppPath);
safe_strcat_path(path, RCT2FilePaths[pathId], sizeof(path));
return path;
}
uint32 get_file_extension_type(const utf8 *path)
{
const utf8 *extension = path_get_extension(path);
if (strcicmp(extension, ".dat") == 0) return FILE_EXTENSION_DAT;
if (strcicmp(extension, ".sc4") == 0) return FILE_EXTENSION_SC4;
if (strcicmp(extension, ".sv4") == 0) return FILE_EXTENSION_SV4;
if (strcicmp(extension, ".td4") == 0) return FILE_EXTENSION_TD4;
if (strcicmp(extension, ".sc6") == 0) return FILE_EXTENSION_SC6;
if (strcicmp(extension, ".sv6") == 0) return FILE_EXTENSION_SV6;
if (strcicmp(extension, ".td6") == 0) return FILE_EXTENSION_TD6;
return FILE_EXTENSION_UNKNOWN;
}