diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index b7715d83b8..ddcb5ca522 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -244,6 +244,10 @@ D41B741D1C210A7A0080A7B9 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B741C1C210A7A0080A7B9 /* libiconv.tbd */; }; D41B74731C2125E50080A7B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D41B74721C2125E50080A7B9 /* Assets.xcassets */; }; D429FF421E36ABCD009342A6 /* tile_inspector.c in Sources */ = {isa = PBXBuildFile; fileRef = D429FF401E36ABCD009342A6 /* tile_inspector.c */; }; + D42E337D1E5C27D600D630AF /* Config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D42E33751E5C27D600D630AF /* Config.cpp */; }; + D42E337E1E5C27D600D630AF /* IniReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D42E33781E5C27D600D630AF /* IniReader.cpp */; }; + D42E337F1E5C27D600D630AF /* IniWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D42E337A1E5C27D600D630AF /* IniWriter.cpp */; }; + D42E33801E5C27D600D630AF /* KeyboardShortcuts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D42E337C1E5C27D600D630AF /* KeyboardShortcuts.cpp */; }; D433A5001E4A861F00D9A6DF /* SawyerChunk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D433A4FA1E4A861F00D9A6DF /* SawyerChunk.cpp */; }; D433A5011E4A861F00D9A6DF /* SawyerChunkReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D433A4FC1E4A861F00D9A6DF /* SawyerChunkReader.cpp */; }; D433A5021E4A861F00D9A6DF /* SawyerChunkWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D433A4FE1E4A861F00D9A6DF /* SawyerChunkWriter.cpp */; }; @@ -266,7 +270,6 @@ D44271FB1CC81B3200D84D28 /* ScreenshotCommands.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44270DA1CC81B3200D84D28 /* ScreenshotCommands.cpp */; }; D44271FC1CC81B3200D84D28 /* SpriteCommands.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44270DB1CC81B3200D84D28 /* SpriteCommands.cpp */; }; D44271FD1CC81B3200D84D28 /* cmdline_sprite.c in Sources */ = {isa = PBXBuildFile; fileRef = D44270DC1CC81B3200D84D28 /* cmdline_sprite.c */; }; - D44271FE1CC81B3200D84D28 /* config.c in Sources */ = {isa = PBXBuildFile; fileRef = D44270DE1CC81B3200D84D28 /* config.c */; }; D44271FF1CC81B3200D84D28 /* Console.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44270E11CC81B3200D84D28 /* Console.cpp */; }; D44272001CC81B3200D84D28 /* Diagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44270E31CC81B3200D84D28 /* Diagnostics.cpp */; }; D44272011CC81B3200D84D28 /* Guard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44270E71CC81B3200D84D28 /* Guard.cpp */; }; @@ -719,6 +722,14 @@ D429FF3F1E36ABB3009342A6 /* tile_inspector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tile_inspector.h; sourceTree = ""; }; D429FF401E36ABCD009342A6 /* tile_inspector.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tile_inspector.c; sourceTree = ""; }; D429FF411E36ABCD009342A6 /* tile_inspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tile_inspector.h; sourceTree = ""; }; + D42E33751E5C27D600D630AF /* Config.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Config.cpp; sourceTree = ""; }; + D42E33761E5C27D600D630AF /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Config.h; sourceTree = ""; }; + D42E33771E5C27D600D630AF /* ConfigEnum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConfigEnum.h; sourceTree = ""; }; + D42E33781E5C27D600D630AF /* IniReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IniReader.cpp; sourceTree = ""; }; + D42E33791E5C27D600D630AF /* IniReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IniReader.h; sourceTree = ""; }; + D42E337A1E5C27D600D630AF /* IniWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IniWriter.cpp; sourceTree = ""; }; + D42E337B1E5C27D600D630AF /* IniWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IniWriter.h; sourceTree = ""; }; + D42E337C1E5C27D600D630AF /* KeyboardShortcuts.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyboardShortcuts.cpp; sourceTree = ""; }; D433A4FA1E4A861F00D9A6DF /* SawyerChunk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SawyerChunk.cpp; path = rct12/SawyerChunk.cpp; sourceTree = ""; }; D433A4FB1E4A861F00D9A6DF /* SawyerChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SawyerChunk.h; path = rct12/SawyerChunk.h; sourceTree = ""; }; D433A4FC1E4A861F00D9A6DF /* SawyerChunkReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SawyerChunkReader.cpp; path = rct12/SawyerChunkReader.cpp; sourceTree = ""; }; @@ -761,8 +772,6 @@ D44270DB1CC81B3200D84D28 /* SpriteCommands.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpriteCommands.cpp; sourceTree = ""; usesTabs = 0; }; D44270DC1CC81B3200D84D28 /* cmdline_sprite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmdline_sprite.c; sourceTree = ""; }; D44270DD1CC81B3200D84D28 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; - D44270DE1CC81B3200D84D28 /* config.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = config.c; sourceTree = ""; }; - D44270DF1CC81B3200D84D28 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; D44270E11CC81B3200D84D28 /* Console.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Console.cpp; sourceTree = ""; usesTabs = 0; }; D44270E21CC81B3200D84D28 /* Console.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Console.hpp; sourceTree = ""; usesTabs = 0; }; D44270E31CC81B3200D84D28 /* Diagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Diagnostics.cpp; sourceTree = ""; usesTabs = 0; }; @@ -1536,6 +1545,7 @@ children = ( D44270CF1CC81B3200D84D28 /* audio */, D44270D61CC81B3200D84D28 /* cmdline */, + D42E33741E5C27D600D630AF /* config */, D44270E01CC81B3200D84D28 /* core */, D44271001CC81B3200D84D28 /* drawing */, D44271181CC81B3200D84D28 /* interface */, @@ -1559,8 +1569,6 @@ D44270D51CC81B3200D84D28 /* cheats.h */, D44270DC1CC81B3200D84D28 /* cmdline_sprite.c */, D44270DD1CC81B3200D84D28 /* common.h */, - D44270DE1CC81B3200D84D28 /* config.c */, - D44270DF1CC81B3200D84D28 /* config.h */, D44270FE1CC81B3200D84D28 /* diagnostic.c */, D44270FF1CC81B3200D84D28 /* diagnostic.h */, D442710E1CC81B3200D84D28 /* editor.c */, @@ -1607,6 +1615,21 @@ path = libxc; sourceTree = ""; }; + D42E33741E5C27D600D630AF /* config */ = { + isa = PBXGroup; + children = ( + D42E33751E5C27D600D630AF /* Config.cpp */, + D42E33761E5C27D600D630AF /* Config.h */, + D42E33771E5C27D600D630AF /* ConfigEnum.h */, + D42E33781E5C27D600D630AF /* IniReader.cpp */, + D42E33791E5C27D600D630AF /* IniReader.h */, + D42E337A1E5C27D600D630AF /* IniWriter.cpp */, + D42E337B1E5C27D600D630AF /* IniWriter.h */, + D42E337C1E5C27D600D630AF /* KeyboardShortcuts.cpp */, + ); + path = config; + sourceTree = ""; + }; D43407BF1D0E14BE00C2B3D4 /* opengl */ = { isa = PBXGroup; children = ( @@ -2723,6 +2746,7 @@ D44272001CC81B3200D84D28 /* Diagnostics.cpp in Sources */, D464FEF11D31A6AA00CBABAC /* SmallSceneryObject.cpp in Sources */, D44272471CC81B3200D84D28 /* ride_ratings.c in Sources */, + D42E337D1E5C27D600D630AF /* Config.cpp in Sources */, D44272721CC81B3200D84D28 /* new_campaign.c in Sources */, C686F93A1CDBC3B7009F9BFC /* spiral_slide.c in Sources */, C686F9421CDBC3B7009F9BFC /* magic_carpet.c in Sources */, @@ -2788,6 +2812,7 @@ D49766831D03B9FE002222CD /* SoftwareDrawingEngine.cpp in Sources */, C6E96E121E04067A0076A04F /* File.cpp in Sources */, D464FEF21D31A6AA00CBABAC /* StexObject.cpp in Sources */, + D42E33801E5C27D600D630AF /* KeyboardShortcuts.cpp in Sources */, C6E96E311E04072F0076A04F /* TitleSequenceManager.cpp in Sources */, C686F9331CDBC3B7009F9BFC /* maze.c in Sources */, C686F9241CDBC3B7009F9BFC /* suspended_swinging_coaster.c in Sources */, @@ -2806,12 +2831,14 @@ D44272571CC81B3200D84D28 /* clear_scenery.c in Sources */, D442727D1CC81B3200D84D28 /* ride_list.c in Sources */, C686F94E1CDBC3B7009F9BFC /* boat_ride.c in Sources */, + D42E337F1E5C27D600D630AF /* IniWriter.cpp in Sources */, D44272891CC81B3200D84D28 /* themes.c in Sources */, C686F9531CDBC3B7009F9BFC /* splash_boats.c in Sources */, C686F9441CDBC3B7009F9BFC /* pirate_ship.c in Sources */, 652747EC1E41CE1B000F36FD /* SawyerEncoding.cpp in Sources */, D44272791CC81B3200D84D28 /* publisher_credits.c in Sources */, C686F91E1CDBC3B7009F9BFC /* reverse_freefall_coaster.c in Sources */, + D42E337E1E5C27D600D630AF /* IniReader.cpp in Sources */, D442723B1CC81B3200D84D28 /* crash.cpp in Sources */, C650B21A1CCABBDD00B4D91C /* tables.cpp in Sources */, D44272291CC81B3200D84D28 /* LanguagePack.cpp in Sources */, @@ -3008,7 +3035,6 @@ C686F9111CDBC3B7009F9BFC /* heartline_twister_coaster.c in Sources */, C6834A111DFDE8E300CE933A /* interop.c in Sources */, C686F9231CDBC3B7009F9BFC /* steeplechase.c in Sources */, - D44271FE1CC81B3200D84D28 /* config.c in Sources */, D44272871CC81B3200D84D28 /* staff_list.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/src/openrct2/OpenRCT2.cpp b/src/openrct2/OpenRCT2.cpp index 72fbb8d749..9de2e9cf6f 100644 --- a/src/openrct2/OpenRCT2.cpp +++ b/src/openrct2/OpenRCT2.cpp @@ -35,7 +35,7 @@ extern "C" { #include "audio/audio.h" - #include "config.h" + #include "config/Config.h" #include "editor.h" #include "game.h" #include "interface/chat.h" diff --git a/src/openrct2/audio/AudioMixer.cpp b/src/openrct2/audio/AudioMixer.cpp index 981d45c0ed..af0a2e6370 100644 --- a/src/openrct2/audio/AudioMixer.cpp +++ b/src/openrct2/audio/AudioMixer.cpp @@ -25,7 +25,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../localisation/localisation.h" #include "../OpenRCT2.h" #include "../platform/platform.h" diff --git a/src/openrct2/audio/audio.cpp b/src/openrct2/audio/audio.cpp index b4d83e54f7..d5efc2cabd 100644 --- a/src/openrct2/audio/audio.cpp +++ b/src/openrct2/audio/audio.cpp @@ -24,7 +24,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../interface/viewport.h" #include "../intro.h" #include "../localisation/language.h" diff --git a/src/openrct2/cheats.c b/src/openrct2/cheats.c index 48ec7a62f9..bdf2bf7b5a 100644 --- a/src/openrct2/cheats.c +++ b/src/openrct2/cheats.c @@ -15,7 +15,7 @@ #pragma endregion #include "cheats.h" -#include "config.h" +#include "config/Config.h" #include "game.h" #include "interface/window.h" #include "localisation/date.h" diff --git a/src/openrct2/cmdline/RootCommands.cpp b/src/openrct2/cmdline/RootCommands.cpp index 62fb60ffb3..b68ca8e7f1 100644 --- a/src/openrct2/cmdline/RootCommands.cpp +++ b/src/openrct2/cmdline/RootCommands.cpp @@ -20,7 +20,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../platform/crash.h" } diff --git a/src/openrct2/config.c b/src/openrct2/config.c deleted file mode 100644 index b329f66bc8..0000000000 --- a/src/openrct2/config.c +++ /dev/null @@ -1,1107 +0,0 @@ -#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 - -#include "config.h" -#include "interface/keyboard_shortcut.h" -#include "interface/themes.h" -#include "interface/viewport.h" -#include "localisation/language.h" -#include "localisation/localisation.h" -#include "network/network.h" -#include "OpenRCT2.h" -#include "util/util.h" - -enum { - CONFIG_VALUE_TYPE_BOOLEAN, - CONFIG_VALUE_TYPE_UINT8, - CONFIG_VALUE_TYPE_UINT16, - CONFIG_VALUE_TYPE_UINT32, - CONFIG_VALUE_TYPE_SINT8, - CONFIG_VALUE_TYPE_SINT16, - CONFIG_VALUE_TYPE_SINT32, - CONFIG_VALUE_TYPE_FLOAT, - CONFIG_VALUE_TYPE_DOUBLE, - CONFIG_VALUE_TYPE_STRING -}; - -size_t _configValueTypeSize[] = { - sizeof(bool), - sizeof(uint8), - sizeof(uint16), - sizeof(uint32), - sizeof(sint8), - sizeof(sint16), - sizeof(sint32), - sizeof(float), - sizeof(double), - sizeof(utf8string) -}; - -typedef union { - sint32 value_sint32; - - bool value_boolean; - sint8 value_sint8; - sint16 value_sint16; - uint8 value_uint8; - uint16 value_uint16; - uint32 value_uint32; - float value_float; - double value_double; - utf8string value_string; -} value_union; - -typedef struct config_enum_definition { - const_utf8string key; - value_union value; -} config_enum_definition; - -#define END_OF_ENUM { NULL, 0 } - -typedef struct config_property_definition { - size_t offset; - const_utf8string property_name; - uint8 type; - value_union default_value; - config_enum_definition *enum_definitions; -} config_property_definition; - -typedef struct config_section_definition { - void *base_address; - const_utf8string section_name; - config_property_definition *property_definitions; - sint32 property_definitions_count; -} config_section_definition; - -#pragma region Enum definitions - -config_enum_definition _drawingEngineFormatEnum[] = { - { "SOFTWARE", DRAWING_ENGINE_SOFTWARE }, - { "SOFTWARE_HWD", DRAWING_ENGINE_SOFTWARE_WITH_HARDWARE_DISPLAY }, - { "OPENGL", DRAWING_ENGINE_OPENGL }, - END_OF_ENUM -}; - -config_enum_definition _measurementFormatEnum[] = { - { "IMPERIAL", MEASUREMENT_FORMAT_IMPERIAL }, - { "METRIC", MEASUREMENT_FORMAT_METRIC }, - { "SI", MEASUREMENT_FORMAT_SI }, - END_OF_ENUM -}; - -config_enum_definition _temperatureFormatEnum[] = { - { "CELSIUS", TEMPERATURE_FORMAT_C }, - { "FAHRENHEIT", TEMPERATURE_FORMAT_F }, - END_OF_ENUM -}; - -config_enum_definition _currencyEnum[] = { - { "GBP", CURRENCY_POUNDS }, - { "USD", CURRENCY_DOLLARS }, - { "FRF", CURRENCY_FRANC }, - { "DEM", CURRENCY_DEUTSCHMARK }, - { "JPY", CURRENCY_YEN }, - { "ESP", CURRENCY_PESETA }, - { "ITL", CURRENCY_LIRA }, - { "NLG", CURRENCY_GUILDERS }, - { "SEK", CURRENCY_KRONA }, - { "EUR", CURRENCY_EUROS }, - { "KRW", CURRENCY_WON }, - { "RUB", CURRENCY_ROUBLE }, - { "CZK", CURRENCY_CZECH_KORUNA }, - { "HKD", CURRENCY_HKD }, - { "TWD", CURRENCY_TWD }, - { "CNY", CURRENCY_YUAN }, - END_OF_ENUM -}; - -config_enum_definition _currencySymbolAffixEnum[] = { - { "PREFIX", CURRENCY_PREFIX }, - { "SUFFIX", CURRENCY_SUFFIX }, - END_OF_ENUM -}; - -config_enum_definition _languageEnum[] = { - { "en-GB", LANGUAGE_ENGLISH_UK }, - { "en-US", LANGUAGE_ENGLISH_US }, - { "de-DE", LANGUAGE_GERMAN }, - { "nl-NL", LANGUAGE_DUTCH }, - { "fr-FR", LANGUAGE_FRENCH }, - { "hu-HU", LANGUAGE_HUNGARIAN }, - { "pl-PL", LANGUAGE_POLISH }, - { "es-ES", LANGUAGE_SPANISH }, - { "sv-SE", LANGUAGE_SWEDISH }, - { "it-IT", LANGUAGE_ITALIAN }, - { "pt-BR", LANGUAGE_PORTUGUESE_BR }, - { "zh-TW", LANGUAGE_CHINESE_TRADITIONAL }, - { "zh-CN", LANGUAGE_CHINESE_SIMPLIFIED }, - { "fi-FI", LANGUAGE_FINNISH }, - { "ko-KR", LANGUAGE_KOREAN }, - { "ru-RU", LANGUAGE_RUSSIAN }, - { "cs-CZ", LANGUAGE_CZECH }, - { "ja-JP", LANGUAGE_JAPANESE }, - { "nb-NO", LANGUAGE_NORWEGIAN }, - { "ca-ES", LANGUAGE_CATALAN }, - END_OF_ENUM -}; - -config_enum_definition _dateFormatEnum[] = { - { "DD/MM/YY", DATE_FORMAT_DMY }, - { "MM/DD/YY", DATE_FORMAT_MDY }, - { "YY/MM/DD", DATE_FORMAT_YMD }, - { "YY/DD/MM", DATE_FORMAT_YDM }, - END_OF_ENUM -}; - -#pragma endregion - -#pragma region Section / property definitions - -config_property_definition _generalDefinitions[] = { - { offsetof(general_configuration, always_show_gridlines), "always_show_gridlines", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, autosave_frequency), "autosave", CONFIG_VALUE_TYPE_UINT8, AUTOSAVE_EVERY_5MINUTES, NULL }, - { offsetof(general_configuration, confirmation_prompt), "confirmation_prompt", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, construction_marker_colour), "construction_marker_colour", CONFIG_VALUE_TYPE_UINT8, false, NULL }, - { offsetof(general_configuration, currency_format), "currency_format", CONFIG_VALUE_TYPE_UINT8, CURRENCY_POUNDS, _currencyEnum }, - { offsetof(general_configuration, custom_currency_rate), "custom_currency_rate", CONFIG_VALUE_TYPE_SINT32, 10, NULL }, - { offsetof(general_configuration, custom_currency_affix), "custom_currency_affix", CONFIG_VALUE_TYPE_SINT8, CURRENCY_SUFFIX, _currencySymbolAffixEnum}, - { offsetof(general_configuration, custom_currency_symbol), "custom_currency_symbol", CONFIG_VALUE_TYPE_STRING, { .value_string = "Ctm" }, NULL }, - { offsetof(general_configuration, edge_scrolling), "edge_scrolling", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, fullscreen_mode), "fullscreen_mode", CONFIG_VALUE_TYPE_UINT8, 0, NULL }, - { offsetof(general_configuration, fullscreen_height), "fullscreen_height", CONFIG_VALUE_TYPE_SINT32, -1, NULL }, - { offsetof(general_configuration, fullscreen_width), "fullscreen_width", CONFIG_VALUE_TYPE_SINT32, -1, NULL }, - { offsetof(general_configuration, rct1_path), "rct1_path", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, - { offsetof(general_configuration, rct2_path), "game_path", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, - { offsetof(general_configuration, landscape_smoothing), "landscape_smoothing", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, language), "language", CONFIG_VALUE_TYPE_UINT16, LANGUAGE_ENGLISH_UK, _languageEnum }, - { offsetof(general_configuration, measurement_format), "measurement_format", CONFIG_VALUE_TYPE_UINT8, MEASUREMENT_FORMAT_METRIC, _measurementFormatEnum }, - { offsetof(general_configuration, play_intro), "play_intro", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, save_plugin_data), "save_plugin_data", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, debugging_tools), "debugging_tools", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, show_height_as_units), "show_height_as_units", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, temperature_format), "temperature_format", CONFIG_VALUE_TYPE_UINT8, TEMPERATURE_FORMAT_C, _temperatureFormatEnum }, - { offsetof(general_configuration, window_height), "window_height", CONFIG_VALUE_TYPE_SINT32, -1, NULL }, - { offsetof(general_configuration, window_snap_proximity), "window_snap_proximity", CONFIG_VALUE_TYPE_UINT8, 5, NULL }, - { offsetof(general_configuration, window_width), "window_width", CONFIG_VALUE_TYPE_SINT32, -1, NULL }, - { offsetof(general_configuration, drawing_engine), "drawing_engine", CONFIG_VALUE_TYPE_UINT8, DRAWING_ENGINE_SOFTWARE, _drawingEngineFormatEnum}, - { offsetof(general_configuration, uncap_fps), "uncap_fps", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, test_unfinished_tracks), "test_unfinished_tracks", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, //Default config setting is false until ghost trains are implemented #4540 - { offsetof(general_configuration, no_test_crashes), "no_test_crashes", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, date_format), "date_format", CONFIG_VALUE_TYPE_UINT8, DATE_FORMAT_DMY, _dateFormatEnum }, - { offsetof(general_configuration, auto_staff_placement), "auto_staff", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, handymen_mow_default), "handymen_mow_default", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, default_inspection_interval), "default_inspection_interval", CONFIG_VALUE_TYPE_UINT8, 2, NULL }, - { offsetof(general_configuration, last_run_version), "last_run_version", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, - { offsetof(general_configuration, invert_viewport_drag), "invert_viewport_drag", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, load_save_sort), "load_save_sort", CONFIG_VALUE_TYPE_UINT8, SORT_NAME_ASCENDING, NULL }, - { offsetof(general_configuration, minimize_fullscreen_focus_loss), "minimize_fullscreen_focus_loss",CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, day_night_cycle), "day_night_cycle", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, //Default config setting is false until the games canvas can be seperated from the effect - { offsetof(general_configuration, enable_light_fx), "enable_light_fx", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, upper_case_banners), "upper_case_banners", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, disable_lightning_effect), "disable_lightning_effect", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, allow_loading_with_incorrect_checksum),"allow_loading_with_incorrect_checksum", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, steam_overlay_pause), "steam_overlay_pause", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, window_scale), "window_scale", CONFIG_VALUE_TYPE_FLOAT, { .value_float = 1.0f }, NULL }, - { offsetof(general_configuration, scale_quality), "scale_quality", CONFIG_VALUE_TYPE_UINT8, 1, NULL }, - { offsetof(general_configuration, use_nn_at_integer_scales), "use_nn_at_integer_scales", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, show_fps), "show_fps", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, trap_cursor), "trap_cursor", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, auto_open_shops), "auto_open_shops", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(general_configuration, scenario_select_mode), "scenario_select_mode", CONFIG_VALUE_TYPE_UINT8, SCENARIO_SELECT_MODE_ORIGIN, NULL }, - { offsetof(general_configuration, scenario_unlocking_enabled), "scenario_unlocking_enabled", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, scenario_hide_mega_park), "scenario_hide_mega_park", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, last_save_game_directory), "last_game_directory", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, - { offsetof(general_configuration, last_save_landscape_directory), "last_landscape_directory", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, - { offsetof(general_configuration, last_save_scenario_directory), "last_scenario_directory", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, - { offsetof(general_configuration, last_save_track_directory), "last_track_directory", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, - { offsetof(general_configuration, window_limit), "window_limit", CONFIG_VALUE_TYPE_UINT8, WINDOW_LIMIT_MAX, NULL }, - { offsetof(general_configuration, zoom_to_cursor), "zoom_to_cursor", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, render_weather_effects), "render_weather_effects", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(general_configuration, render_weather_gloom), "render_weather_gloom", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, -}; - -config_property_definition _interfaceDefinitions[] = { - { offsetof(interface_configuration, toolbar_show_finances), "toolbar_show_finances", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(interface_configuration, toolbar_show_research), "toolbar_show_research", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(interface_configuration, toolbar_show_cheats), "toolbar_show_cheats", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(interface_configuration, toolbar_show_news), "toolbar_show_news", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(interface_configuration, select_by_track_type), "select_by_track_type", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(interface_configuration, console_small_font), "console_small_font", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(interface_configuration, current_theme_preset), "current_theme", CONFIG_VALUE_TYPE_STRING, { .value_string = "*RCT2" }, NULL }, - { offsetof(interface_configuration, current_title_sequence_preset), "current_title_sequence", CONFIG_VALUE_TYPE_STRING, { .value_string = "*OPENRCT2" },NULL }, - { offsetof(interface_configuration, object_selection_filter_flags), "object_selection_filter_flags",CONFIG_VALUE_TYPE_UINT32, 0x7EF, NULL }, -}; - -config_property_definition _soundDefinitions[] = { - { offsetof(sound_configuration, master_volume), "master_volume", CONFIG_VALUE_TYPE_UINT8, 100, NULL }, - { offsetof(sound_configuration, title_music), "title_music", CONFIG_VALUE_TYPE_UINT8, 2, NULL }, - { offsetof(sound_configuration, sound_enabled), "sound", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(sound_configuration, sound_volume), "sound_volume", CONFIG_VALUE_TYPE_UINT8, 100, NULL }, - { offsetof(sound_configuration, ride_music_enabled), "ride_music", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(sound_configuration, ride_music_volume), "ride_music_volume", CONFIG_VALUE_TYPE_UINT8, 100, NULL }, - { offsetof(sound_configuration, audio_focus), "audio_focus", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(sound_configuration, device), "audio_device", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, -}; - -config_property_definition _twitchDefinitions[] = { - { offsetof(twitch_configuration, channel), "channel", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, - { offsetof(twitch_configuration, enable_follower_peep_names), "follower_peep_names", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(twitch_configuration, enable_follower_peep_tracking), "follower_peep_tracking", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(twitch_configuration, enable_chat_peep_names), "chat_peep_names", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(twitch_configuration, enable_chat_peep_tracking), "chat_peep_tracking", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(twitch_configuration, enable_news), "news", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL } -}; - -config_property_definition _networkDefinitions[] = { - { offsetof(network_configuration, player_name), "player_name", CONFIG_VALUE_TYPE_STRING, {.value_string = "Player" }, NULL }, - { offsetof(network_configuration, default_port), "default_port", CONFIG_VALUE_TYPE_UINT32, NETWORK_DEFAULT_PORT, NULL }, - { offsetof(network_configuration, default_password), "default_password", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, - { offsetof(network_configuration, stay_connected), "stay_connected", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(network_configuration, advertise), "advertise", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(network_configuration, maxplayers), "maxplayers", CONFIG_VALUE_TYPE_UINT8, 16, NULL }, - { offsetof(network_configuration, server_name), "server_name", CONFIG_VALUE_TYPE_STRING, {.value_string = "Server" }, NULL }, - { offsetof(network_configuration, server_description), "server_description", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, - { offsetof(network_configuration, server_greeting), "server_greeting", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, - { offsetof(network_configuration, master_server_url), "master_server_url", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, - { offsetof(network_configuration, provider_name), "provider_name", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, - { offsetof(network_configuration, provider_email), "provider_email", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, - { offsetof(network_configuration, provider_website), "provider_website", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, - { offsetof(network_configuration, known_keys_only), "known_keys_only", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(network_configuration, log_chat), "log_chat", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, -}; - -config_property_definition _notificationsDefinitions[] = { - { offsetof(notification_configuration, park_award), "park_award", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, park_marketing_campaign_finished), "park_marketing_campaign_finished", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, park_warnings), "park_warnings", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, park_rating_warnings), "park_rating_warnings", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, ride_broken_down), "ride_broken_down", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, ride_crashed), "ride_crashed", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, ride_warnings), "ride_warnings", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, ride_researched), "ride_researched", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, guest_warnings), "guest_warnings", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, guest_lost), "guest_lost", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(notification_configuration, guest_left_park), "guest_entered_left_park", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, guest_queuing_for_ride), "guest_queuing_for_ride", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, guest_on_ride), "guest_on_ride", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, guest_left_ride), "guest_left_ride", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, guest_bought_item), "guest_bought_item", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, guest_used_facility), "guest_used_facility", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, - { offsetof(notification_configuration, guest_died), "guest_died", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, -}; - -config_property_definition _fontsDefinitions[] = { - { offsetof(font_configuration, file_name), "file_name", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, - { offsetof(font_configuration, font_name), "font_name", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, - { offsetof(font_configuration, x_offset), "x_offset", CONFIG_VALUE_TYPE_SINT8, 0, NULL }, - { offsetof(font_configuration, y_offset), "y_offset", CONFIG_VALUE_TYPE_SINT8, -1, NULL }, - { offsetof(font_configuration, size_tiny), "size_tiny", CONFIG_VALUE_TYPE_UINT8, 8, NULL }, - { offsetof(font_configuration, size_small), "size_small", CONFIG_VALUE_TYPE_UINT8, 10, NULL }, - { offsetof(font_configuration, size_medium), "size_medium", CONFIG_VALUE_TYPE_UINT8, 11, NULL }, - { offsetof(font_configuration, size_big), "size_big", CONFIG_VALUE_TYPE_UINT8, 12, NULL }, - { offsetof(font_configuration, height_tiny), "height_tiny", CONFIG_VALUE_TYPE_UINT8, 6, NULL }, - { offsetof(font_configuration, height_small), "height_small", CONFIG_VALUE_TYPE_UINT8, 12, NULL }, - { offsetof(font_configuration, height_medium), "height_medium", CONFIG_VALUE_TYPE_UINT8, 12, NULL }, - { offsetof(font_configuration, height_big), "height_big", CONFIG_VALUE_TYPE_UINT8, 20, NULL } -}; - -config_section_definition _sectionDefinitions[] = { - { &gConfigGeneral, "general", _generalDefinitions, countof(_generalDefinitions) }, - { &gConfigInterface, "interface", _interfaceDefinitions, countof(_interfaceDefinitions) }, - { &gConfigSound, "sound", _soundDefinitions, countof(_soundDefinitions) }, - { &gConfigTwitch, "twitch", _twitchDefinitions, countof(_twitchDefinitions) }, - { &gConfigNetwork, "network", _networkDefinitions, countof(_networkDefinitions) }, - { &gConfigNotifications, "notifications", _notificationsDefinitions, countof(_notificationsDefinitions) }, - { &gConfigFonts, "fonts", _fontsDefinitions, countof(_fontsDefinitions) } -}; - -#pragma endregion - -general_configuration gConfigGeneral; -interface_configuration gConfigInterface; -sound_configuration gConfigSound; -twitch_configuration gConfigTwitch; -network_configuration gConfigNetwork; -notification_configuration gConfigNotifications; -font_configuration gConfigFonts; - -static bool config_open(const utf8string path); -static bool config_save(const utf8string path); -static void config_read_properties(config_section_definition **currentSection, const_utf8string line); -static void config_save_property_value(SDL_RWops *file, uint8 type, value_union *value); -static bool config_read_enum(void *dest, sint32 destSize, const utf8 *key, sint32 keySize, config_enum_definition *enumDefinitions); -static void config_write_enum(SDL_RWops *file, uint8 type, value_union *value, config_enum_definition *enumDefinitions); - -static void utf8_skip_whitespace(utf8 **outch); -static void utf8_skip_non_whitespace(utf8 **outch); - -static sint32 rwopsreadc(SDL_RWops *file) -{ - sint32 c = 0; - if (SDL_RWread(file, &c, 1, 1) != 1) - c = EOF; - return c; -} - -static void rwopswritec(SDL_RWops *file, char c) -{ - SDL_RWwrite(file, &c, 1, 1); -} - -static void rwopswritestr(SDL_RWops *file, const char *str) -{ - SDL_RWwrite(file, str, strlen(str), 1); -} - -static void rwopsprintf(SDL_RWops *file, const char *format, ...) -{ - va_list args; - va_start(args, format); - - char buffer[64]; - vsnprintf(buffer, 64, format, args); - - SDL_RWwrite(file, buffer, strlen(buffer), 1); - - va_end(args); -} - -static void rwopswritenewline(SDL_RWops *file) -{ - rwopswritestr(file, PLATFORM_NEWLINE); -} - -static void rwopswritestresc(SDL_RWops *file, const char *str) { - sint32 length = 0; - for (const char *c = str; *c != '\0'; ++c) { - if (*c == '\\') length += 2; - else ++length; - } - - char *escaped = malloc(length + 1); - sint32 j=0; - for (const char *c = str; *c != '\0'; ++c) { - if (*c == '\\') escaped[j++] = '\\'; - escaped[j++] = *c; - } - escaped[length] = '\0'; - - rwopswritestr(file, escaped); - SafeFree(escaped); -} - -void config_set_defaults() -{ - sint32 i, j; - - for (i = 0; i < countof(_sectionDefinitions); i++) { - config_section_definition *section = &_sectionDefinitions[i]; - for (j = 0; j < section->property_definitions_count; j++) { - config_property_definition *property = §ion->property_definitions[j]; - value_union *destValue = (value_union*)((size_t)section->base_address + (size_t)property->offset); - - // Special dynamic defaults - if (strcmp(property->property_name, "language") == 0){ - destValue->value_uint16 = platform_get_locale_language(); - if (destValue->value_uint16 == LANGUAGE_UNDEFINED) - memcpy(destValue, &property->default_value, _configValueTypeSize[property->type]); - } - else if (strcmp(property->property_name, "currency_format") == 0){ - destValue->value_uint8 = platform_get_locale_currency(); - } - else if (strcmp(property->property_name, "measurement_format") == 0){ - destValue->value_uint8 = platform_get_locale_measurement_format(); - } - else if (strcmp(property->property_name, "temperature_format") == 0){ - destValue->value_uint8 = platform_get_locale_temperature_format(); - } - else if (strcmp(property->property_name, "player_name") == 0) { - utf8* username = platform_get_username(); - - if (username) { - destValue->value_string = _strdup(username); - } else { - destValue->value_string = _strdup(language_get_string(STR_MULTIPLAYER_DEFAULT_NAME)); - } - } - else { - // Use static default - if (property->type == CONFIG_VALUE_TYPE_STRING) { - // Copy the string to new memory - const utf8 *src = property->default_value.value_string; - const utf8 **dst = (const utf8**)&(destValue->value_string); - if (src != NULL) { - *dst = _strdup(property->default_value.value_string); - } - } else { - memcpy(destValue, &property->default_value, _configValueTypeSize[property->type]); - } - } - } - } -} - -void config_release() -{ - for (sint32 i = 0; i < countof(_sectionDefinitions); i++) { - config_section_definition *section = &_sectionDefinitions[i]; - for (sint32 j = 0; j < section->property_definitions_count; j++) { - config_property_definition *property = §ion->property_definitions[j]; - value_union *destValue = (value_union*)((size_t)section->base_address + (size_t)property->offset); - if (property->type == CONFIG_VALUE_TYPE_STRING) { - utf8 **dst = (utf8**)&(destValue->value_string); - SafeFree(*dst); - } - } - } -} - -void config_get_default_path(utf8 *outPath, size_t size) -{ - platform_get_user_directory(outPath, NULL, size); - safe_strcat_path(outPath, "config.ini", size); -} - -bool config_open_default() -{ - utf8 path[MAX_PATH]; - - config_get_default_path(path, sizeof(path)); - if (config_open(path)) { - currency_load_custom_currency_config(); - return true; - } - - return false; -} - -bool config_save_default() -{ - utf8 path[MAX_PATH]; - - config_get_default_path(path, sizeof(path)); - if (config_save(path)) { - return true; - } - - return false; -} - -bool config_open(const utf8string path) -{ - SDL_RWops *file; - utf8string lineBuffer; - size_t lineBufferCapacity; - size_t lineLength; - sint32 c; - config_section_definition *currentSection; - - file = SDL_RWFromFile(path, "rb"); - if (file == NULL) - return false; - - currentSection = NULL; - lineBufferCapacity = 64; - lineBuffer = malloc(lineBufferCapacity); - lineLength = 0; - - // Skim UTF-8 byte order mark - SDL_RWread(file, lineBuffer, 3, 1); - if (!utf8_is_bom(lineBuffer)) - SDL_RWseek(file, 0, RW_SEEK_SET); - - while ((c = rwopsreadc(file)) != EOF) { - if (c == '\n' || c == '\r') { - lineBuffer[lineLength] = 0; - config_read_properties(¤tSection, (const_utf8string)lineBuffer); - lineLength = 0; - } else { - lineBuffer[lineLength++] = c; - } - - if (lineLength >= lineBufferCapacity) { - lineBufferCapacity *= 2; - lineBuffer = realloc(lineBuffer, lineBufferCapacity); - } - } - - if (lineLength > 0) { - lineBuffer[lineLength++] = 0; - config_read_properties(¤tSection, lineBuffer); - } - - free(lineBuffer); - SDL_RWclose(file); - - // Window limit must be kept within valid range. - if (gConfigGeneral.window_limit < WINDOW_LIMIT_MIN) { - gConfigGeneral.window_limit = WINDOW_LIMIT_MIN; - } - else if (gConfigGeneral.window_limit > WINDOW_LIMIT_MAX) { - gConfigGeneral.window_limit = WINDOW_LIMIT_MAX; - } - - return true; -} - -bool config_save(const utf8string path) -{ - SDL_RWops *file; - sint32 i, j; - value_union *value; - - file = SDL_RWFromFile(path, "wb"); - if (file == NULL) { - log_error("Unable to write to config file."); - return false; - } - - for (i = 0; i < countof(_sectionDefinitions); i++) { - config_section_definition *section = &_sectionDefinitions[i]; - - rwopswritec(file, '['); - rwopswritestr(file, section->section_name); - rwopswritec(file, ']'); - rwopswritenewline(file); - - for (j = 0; j < section->property_definitions_count; j++) { - config_property_definition *property = §ion->property_definitions[j]; - - rwopswritestr(file, property->property_name); - rwopswritestr(file, " = "); - - value = (value_union*)((size_t)section->base_address + (size_t)property->offset); - if (property->enum_definitions != NULL) - config_write_enum(file, property->type, value, property->enum_definitions); - else - config_save_property_value(file, property->type, value); - rwopswritenewline(file); - } - rwopswritenewline(file); - } - - SDL_RWclose(file); - return true; -} - -static void config_save_property_value(SDL_RWops *file, uint8 type, value_union *value) -{ - switch (type) { - case CONFIG_VALUE_TYPE_BOOLEAN: - if (value->value_boolean) rwopswritestr(file, "true"); - else rwopswritestr(file, "false"); - break; - case CONFIG_VALUE_TYPE_UINT8: - rwopsprintf(file, "%u", value->value_uint8); - break; - case CONFIG_VALUE_TYPE_UINT16: - rwopsprintf(file, "%u", value->value_uint16); - break; - case CONFIG_VALUE_TYPE_UINT32: - rwopsprintf(file, "%lu", value->value_uint32); - break; - case CONFIG_VALUE_TYPE_SINT8: - rwopsprintf(file, "%d", value->value_sint8); - break; - case CONFIG_VALUE_TYPE_SINT16: - rwopsprintf(file, "%d", value->value_sint16); - break; - case CONFIG_VALUE_TYPE_SINT32: - rwopsprintf(file, "%ld", value->value_sint32); - break; - case CONFIG_VALUE_TYPE_FLOAT: - rwopsprintf(file, "%.3f", value->value_float); - break; - case CONFIG_VALUE_TYPE_DOUBLE: - rwopsprintf(file, "%.6f", value->value_double); - break; - case CONFIG_VALUE_TYPE_STRING: - rwopswritec(file, '"'); - if (value->value_string != NULL) { - rwopswritestresc(file, value->value_string); - } - rwopswritec(file, '"'); - break; - } -} - -static bool config_get_section(const utf8string line, const utf8 **sectionName, sint32 *sectionNameSize) -{ - utf8 *ch; - sint32 c; - - ch = line; - utf8_skip_whitespace(&ch); - if (*ch != '[') return false; - *sectionName = ++ch; - - while ((c = utf8_get_next(ch, (const utf8**)&ch)) != 0) { - if (c == '#') return false; - if (c == '[') return false; - if (c == ' ') break; - if (c == ']') break; - } - - *sectionNameSize = (sint32)(ch - *sectionName - 1); - return true; -} - -static bool config_get_property_name_value(const utf8string line, utf8 **propertyName, sint32 *propertyNameSize, utf8 **value, sint32 *valueSize) -{ - utf8 *ch, *clast; - sint32 c; - bool quotes; - - ch = line; - utf8_skip_whitespace(&ch); - - if (*ch == 0) return false; - *propertyName = ch; - - bool equals = false; - while ((c = utf8_get_next(ch, (const utf8**)&ch)) != 0) { - if (isspace(c) || c == '=') { - if (c == '=') equals = true; - *propertyNameSize = (sint32)(ch - *propertyName - 1); - break; - } else if (c == '#') { - return false; - } - } - - if (*ch == 0) return false; - utf8_skip_whitespace(&ch); - if (!equals) { - if (*ch != '=') return false; - ch++; - utf8_skip_whitespace(&ch); - } - if (*ch == 0) return false; - - if (*ch == '"') { - ch++; - quotes = true; - } else { - quotes = false; - } - *value = ch; - - clast = ch; - while ((c = utf8_get_next(ch, (const utf8**)&ch)) != 0) { - if (!quotes) { - if (c == '#') break; - if (c != ' ') clast = ch; - } - } - if (!quotes) *valueSize = (sint32)(clast - *value); - else *valueSize = (sint32)(ch - *value - 1); - if (quotes) (*valueSize)--; - return true; -} - -static config_section_definition *config_get_section_def(const utf8 *name, sint32 size) -{ - sint32 i; - - for (i = 0; i < countof(_sectionDefinitions); i++) { - const_utf8string sectionName = _sectionDefinitions[i].section_name; - sint32 sectionNameSize = (sint32)strnlen(sectionName, size); - if (sectionNameSize == size && sectionName[size] == 0 && _strnicmp(sectionName, name, size) == 0) - return &_sectionDefinitions[i]; - } - - return NULL; -} - -static config_property_definition *config_get_property_def(config_section_definition *section, const utf8 *name, sint32 size) -{ - sint32 i; - - for (i = 0; i < section->property_definitions_count; i++) { - const_utf8string propertyName = section->property_definitions[i].property_name; - sint32 propertyNameSize = (sint32)strnlen(propertyName, size); - if (propertyNameSize == size && propertyName[size] == 0 && _strnicmp(propertyName, name, size) == 0) - { - return §ion->property_definitions[i]; - } - } - - return NULL; -} - -static utf8string escape_string(const utf8 *value, sint32 valueSize) { - sint32 length = 0; - bool backslash = false; - for (sint32 i=0; i < valueSize; ++i) { - if (value[i] == '\\') { - if (backslash) backslash = false; - else ++length, backslash = true; - } else ++length, backslash = false; - } - utf8string escaped = malloc(length + 1); - - sint32 j=0; - backslash = false; - for (sint32 i=0; i < valueSize; ++i) { - if (value[i] == '\\') { - if (backslash) backslash = false; - else escaped[j++] = value[i], backslash = true; - } else escaped[j++] = value[i], backslash = false; - } - escaped[length] = '\0'; - - return escaped; -} - -static void config_set_property(const config_section_definition *section, const config_property_definition *property, const utf8 *value, sint32 valueSize) -{ - value_union *destValue = (value_union*)((size_t)section->base_address + (size_t)property->offset); - - if (property->enum_definitions != NULL) - if (config_read_enum(destValue, (sint32)_configValueTypeSize[property->type], value, valueSize, property->enum_definitions)) - return; - - switch (property->type) { - case CONFIG_VALUE_TYPE_BOOLEAN: - if (_strnicmp(value, "false", valueSize) == 0) destValue->value_boolean = false; - else if (_strnicmp(value, "true", valueSize) == 0) destValue->value_boolean = true; - else destValue->value_boolean = strtol(value, NULL, 0) != 0; - break; - case CONFIG_VALUE_TYPE_UINT8: - destValue->value_uint8 = (uint8)strtol(value, NULL, 0); - break; - case CONFIG_VALUE_TYPE_UINT16: - destValue->value_uint16 = (uint16)strtol(value, NULL, 0); - break; - case CONFIG_VALUE_TYPE_UINT32: - destValue->value_uint32 = (uint32)strtol(value, NULL, 0); - break; - case CONFIG_VALUE_TYPE_SINT8: - destValue->value_sint8 = (sint8)strtol(value, NULL, 0); - break; - case CONFIG_VALUE_TYPE_SINT16: - destValue->value_sint16 = (sint16)strtol(value, NULL, 0); - break; - case CONFIG_VALUE_TYPE_SINT32: - destValue->value_sint32 = (sint32)strtol(value, NULL, 0); - break; - case CONFIG_VALUE_TYPE_FLOAT: - destValue->value_float = strtof(value, NULL); - break; - case CONFIG_VALUE_TYPE_DOUBLE: - destValue->value_double = strtod(value, NULL); - break; - case CONFIG_VALUE_TYPE_STRING: - SafeFree(destValue->value_string); - destValue->value_string = escape_string(value, valueSize); - break; - } -} - -static void config_read_properties(config_section_definition **currentSection, const_utf8string line) -{ - utf8 *ch = (utf8*)line; - utf8_skip_whitespace(&ch); - - if (*ch == '[') { - const utf8 *sectionName; - sint32 sectionNameSize; - if (config_get_section(ch, §ionName, §ionNameSize)) - *currentSection = config_get_section_def(sectionName, sectionNameSize); - } else { - if (*currentSection != NULL) { - utf8 *propertyName, *value; - sint32 propertyNameSize = 0, valueSize; - if (config_get_property_name_value(ch, &propertyName, &propertyNameSize, &value, &valueSize)) { - config_property_definition *property; - property = config_get_property_def(*currentSection, propertyName, propertyNameSize); - if (property != NULL) - config_set_property(*currentSection, property, value, valueSize); - } - } - } -} - -static bool config_read_enum(void *dest, sint32 destSize, const utf8 *key, sint32 keySize, config_enum_definition *enumDefinitions) -{ - while (enumDefinitions->key != NULL) { - if (strlen(enumDefinitions->key) == (size_t)keySize && _strnicmp(enumDefinitions->key, key, keySize) == 0) { - memcpy(dest, &enumDefinitions->value.value_uint32, destSize); - return true; - } - enumDefinitions++; - } - return false; -} - -static void config_write_enum(SDL_RWops *file, uint8 type, value_union *value, config_enum_definition *enumDefinitions) -{ - uint32 enumValue = (value->value_uint32) & ((1 << (_configValueTypeSize[type] * 8)) - 1); - while (enumDefinitions->key != NULL) { - if (enumDefinitions->value.value_uint32 == enumValue) { - rwopswritestr(file, enumDefinitions->key); - return; - } - enumDefinitions++; - } - config_save_property_value(file, type, value); -} - -static void utf8_skip_whitespace(utf8 **outch) -{ - utf8 *ch; - while (**outch != 0) { - ch = *outch; - if (!isspace(utf8_get_next(*outch, (const utf8**)outch))) { - *outch = ch; - break; - } - } -} - -static void utf8_skip_non_whitespace(utf8 **outch) -{ - while (**outch != 0) { - if (isspace(utf8_get_next(*outch, (const utf8**)outch))) - break; - } -} - -/* - -Code reserved for when we want more intelligent saving of config file which preserves comments and layout - -enum { - CONFIG_LINE_TYPE_WHITESPACE, - CONFIG_LINE_TYPE_COMMENT, - CONFIG_LINE_TYPE_SECTION, - CONFIG_LINE_TYPE_PROPERTY, - CONFIG_LINE_TYPE_INVALID -}; - -typedef struct { - uint8 type; - utf8string line; -} config_line; - -static config_line *_configLines = NULL; - -*/ - -/** - * Attempts to find the RCT2 installation directory. - * This should be created from some other resource when OpenRCT2 grows. - * @param resultPath Pointer to where the absolute path of the RCT2 installation directory will be copied to. - * @returns 1 if successful, otherwise 0. - */ -static bool config_find_rct2_path(utf8 *resultPath) -{ - sint32 i; - - log_verbose("searching common installation locations."); - - const utf8 *searchLocations[] = { - "C:\\Program Files\\Infogrames\\RollerCoaster Tycoon 2", - "C:\\Program Files (x86)\\Infogrames\\RollerCoaster Tycoon 2", - "C:\\Program Files\\Infogrames Interactive\\RollerCoaster Tycoon 2", - "C:\\Program Files (x86)\\Infogrames Interactive\\RollerCoaster Tycoon 2", - "C:\\Program Files\\Atari\\RollerCoaster Tycoon 2", - "C:\\Program Files (x86)\\Atari\\RollerCoaster Tycoon 2", - "C:\\GOG Games\\RollerCoaster Tycoon 2 Triple Thrill Pack", - "C:\\Program Files\\GalaxyClient\\Games\\RollerCoaster Tycoon 2 Triple Thrill Pack", - "C:\\Program Files (x86)\\GalaxyClient\\Games\\RollerCoaster Tycoon 2 Triple Thrill Pack", - "C:\\Program Files\\Steam\\steamapps\\common\\Rollercoaster Tycoon 2", - "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Rollercoaster Tycoon 2", - gExePath - }; - - for (i = 0; i < countof(searchLocations); i++) { - if (platform_original_game_data_exists(searchLocations[i])) { - safe_strcpy(resultPath, searchLocations[i], MAX_PATH); - return true; - } - } - - return false; -} - -bool config_find_or_browse_install_directory() -{ - utf8 path[MAX_PATH]; - utf8 *installPath; - - if (config_find_rct2_path(path)) { - SafeFree(gConfigGeneral.rct2_path); - gConfigGeneral.rct2_path = malloc(strlen(path) + 1); - safe_strcpy(gConfigGeneral.rct2_path, path, MAX_PATH); - } else { - if (gOpenRCT2Headless) { - return false; - } - while (1) { - platform_show_messagebox("OpenRCT2 needs files from the original RollerCoaster Tycoon 2 in order to work. Please select the directory where you installed RollerCoaster Tycoon 2."); - installPath = platform_open_directory_browser("Please select your RCT2 directory"); - if (installPath == NULL) - return false; - - SafeFree(gConfigGeneral.rct2_path); - gConfigGeneral.rct2_path = installPath; - - if (platform_original_game_data_exists(installPath)) - return true; - - utf8 message[MAX_PATH]; - snprintf(message, MAX_PATH, "Could not find %s" PATH_SEPARATOR "Data" PATH_SEPARATOR "g1.dat at this path", installPath); - platform_show_messagebox(message); - } - } - - return true; -} - -#pragma region Shortcuts - -// Current keyboard shortcuts -uint16 gShortcutKeys[SHORTCUT_COUNT]; - -// Default keyboard shortcuts -static const uint16 _defaultShortcutKeys[SHORTCUT_COUNT] = { - SDL_SCANCODE_BACKSPACE, // SHORTCUT_CLOSE_TOP_MOST_WINDOW - SHIFT | SDL_SCANCODE_BACKSPACE, // SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS - SDL_SCANCODE_ESCAPE, // SHORTCUT_CANCEL_CONSTRUCTION_MODE - SDL_SCANCODE_PAUSE, // SHORTCUT_PAUSE_GAME - SDL_SCANCODE_PAGEUP, // SHORTCUT_ZOOM_VIEW_OUT - SDL_SCANCODE_PAGEDOWN, // SHORTCUT_ZOOM_VIEW_IN - SDL_SCANCODE_RETURN, // SHORTCUT_ROTATE_VIEW_CLOCKWISE - SHIFT | SDL_SCANCODE_RETURN, // SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE - SDL_SCANCODE_Z, // SHORTCUT_ROTATE_CONSTRUCTION_OBJECT - SDL_SCANCODE_1, // SHORTCUT_UNDERGROUND_VIEW_TOGGLE - SDL_SCANCODE_H, // SHORTCUT_REMOVE_BASE_LAND_TOGGLE - SDL_SCANCODE_V, // SHORTCUT_REMOVE_VERTICAL_LAND_TOGGLE - SDL_SCANCODE_3, // SHORTCUT_SEE_THROUGH_RIDES_TOGGLE - SDL_SCANCODE_4, // SHORTCUT_SEE_THROUGH_SCENERY_TOGGLE - SDL_SCANCODE_5, // SHORTCUT_INVISIBLE_SUPPORTS_TOGGLE - SDL_SCANCODE_6, // SHORTCUT_INVISIBLE_PEOPLE_TOGGLE - SDL_SCANCODE_8, // SHORTCUT_HEIGHT_MARKS_ON_LAND_TOGGLE - SDL_SCANCODE_9, // SHORTCUT_HEIGHT_MARKS_ON_RIDE_TRACKS_TOGGLE - SDL_SCANCODE_0, // SHORTCUT_HEIGHT_MARKS_ON_PATHS_TOGGLE - SDL_SCANCODE_F1, // SHORTCUT_ADJUST_LAND - SDL_SCANCODE_F2, // SHORTCUT_ADJUST_WATER - SDL_SCANCODE_F3, // SHORTCUT_BUILD_SCENERY - SDL_SCANCODE_F4, // SHORTCUT_BUILD_PATHS - SDL_SCANCODE_F5, // SHORTCUT_BUILD_NEW_RIDE - SDL_SCANCODE_F, // SHORTCUT_SHOW_FINANCIAL_INFORMATION - SDL_SCANCODE_D, // SHORTCUT_SHOW_RESEARCH_INFORMATION - SDL_SCANCODE_R, // SHORTCUT_SHOW_RIDES_LIST - SDL_SCANCODE_P, // SHORTCUT_SHOW_PARK_INFORMATION - SDL_SCANCODE_G, // SHORTCUT_SHOW_GUEST_LIST - SDL_SCANCODE_S, // SHORTCUT_SHOW_STAFF_LIST - SDL_SCANCODE_M, // SHORTCUT_SHOW_RECENT_MESSAGES - SDL_SCANCODE_TAB, // SHORTCUT_SHOW_MAP - PLATFORM_MODIFIER | SDL_SCANCODE_S, // SHORTCUT_SCREENSHOT - - // New - SDL_SCANCODE_MINUS, // SHORTCUT_REDUCE_GAME_SPEED, - SDL_SCANCODE_EQUALS, // SHORTCUT_INCREASE_GAME_SPEED, - PLATFORM_MODIFIER | ALT | SDL_SCANCODE_C, // SHORTCUT_OPEN_CHEAT_WINDOW, - SDL_SCANCODE_T, // SHORTCUT_REMOVE_TOP_BOTTOM_TOOLBAR_TOGGLE, - SDL_SCANCODE_UP, // SHORTCUT_SCROLL_MAP_UP - SDL_SCANCODE_LEFT, // SHORTCUT_SCROLL_MAP_LEFT - SDL_SCANCODE_DOWN, // SHORTCUT_SCROLL_MAP_DOWN - SDL_SCANCODE_RIGHT, // SHORTCUT_SCROLL_MAP_RIGHT - SDL_SCANCODE_C, // SHORTCUT_OPEN_CHAT_WINDOW - PLATFORM_MODIFIER | SDL_SCANCODE_F10, // SHORTCUT_QUICK_SAVE_GAME - - SHORTCUT_UNDEFINED, // SHORTCUT_SHOW_OPTIONS - SHORTCUT_UNDEFINED, // SHORTCUT_MUTE_SOUND - ALT | SDL_SCANCODE_RETURN, // SHORTCUT_WINDOWED_MODE_TOGGLE - SHORTCUT_UNDEFINED, // SHORTCUT_SHOW_MULTIPLAYER - SHORTCUT_UNDEFINED, // SHORTCUT_PAINT_ORIGINAL_TOGGLE - SHORTCUT_UNDEFINED, // SHORTCUT_DEBUG_PAINT_TOGGLE - SHORTCUT_UNDEFINED, // SHORTCUT_SEE_THROUGH_PATHS_TOGGLE -}; - -#define SHORTCUT_FILE_VERSION 1 - -/** - * - * rct2: 0x006E3604 - */ -void config_reset_shortcut_keys() -{ - memcpy(gShortcutKeys, _defaultShortcutKeys, sizeof(gShortcutKeys)); -} - -static void config_shortcut_keys_get_path(utf8 *outPath, size_t size) -{ - platform_get_user_directory(outPath, NULL, size); - safe_strcat_path(outPath, "hotkeys.cfg", size); -} - -bool config_shortcut_keys_load() -{ - utf8 path[MAX_PATH]; - SDL_RWops *file; - bool result; - uint16 version; - - config_shortcut_keys_get_path(path, sizeof(path)); - - file = SDL_RWFromFile(path, "rb"); - if (file != NULL) { - result = SDL_RWread(file, &version, sizeof(version), 1) == 1; - if (result && version == SHORTCUT_FILE_VERSION) { - for (sint32 i = 0; i < SHORTCUT_COUNT; i++) { - if (SDL_RWread(file, &gShortcutKeys[i], sizeof(uint16), 1) != 1) { - break; - } - } - } else { - result = false; - } - SDL_RWclose(file); - } else { - result = false; - } - - return result; -} - -bool config_shortcut_keys_save() -{ - const uint16 version = SHORTCUT_FILE_VERSION; - - utf8 path[MAX_PATH]; - SDL_RWops *file; - bool result; - - config_shortcut_keys_get_path(path, sizeof(path)); - - file = SDL_RWFromFile(path, "wb"); - if (file != NULL) { - result = SDL_RWwrite(file, &version, sizeof(version), 1) == 1; - if (result) { - result = SDL_RWwrite(file, gShortcutKeys, sizeof(gShortcutKeys), 1) == 1; - } - SDL_RWclose(file); - } else { - result = false; - } - - return result; -} - -#pragma endregion diff --git a/src/openrct2/config.h b/src/openrct2/config.h deleted file mode 100644 index c04568503e..0000000000 --- a/src/openrct2/config.h +++ /dev/null @@ -1,333 +0,0 @@ -#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 - -#ifndef _CONFIG_H_ -#define _CONFIG_H_ - -#include "common.h" -#include "localisation/currency.h" -#include "platform/platform.h" - -enum { - CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES = (1 << 0), - CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS = (1 << 1), - CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE = (1 << 2), - CONFIG_FLAG_SAVE_PLUGIN_DATA = (1 << 3) -}; - -enum { - SHORTCUT_CLOSE_TOP_MOST_WINDOW, - SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS, - SHORTCUT_CANCEL_CONSTRUCTION_MODE, - SHORTCUT_PAUSE_GAME, - SHORTCUT_ZOOM_VIEW_OUT, - SHORTCUT_ZOOM_VIEW_IN, - SHORTCUT_ROTATE_VIEW_CLOCKWISE, - SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE, - SHORTCUT_ROTATE_CONSTRUCTION_OBJECT, - SHORTCUT_UNDERGROUND_VIEW_TOGGLE, - SHORTCUT_REMOVE_BASE_LAND_TOGGLE, - SHORTCUT_REMOVE_VERTICAL_LAND_TOGGLE, - SHORTCUT_SEE_THROUGH_RIDES_TOGGLE, - SHORTCUT_SEE_THROUGH_SCENERY_TOGGLE, - SHORTCUT_INVISIBLE_SUPPORTS_TOGGLE, - SHORTCUT_INVISIBLE_PEOPLE_TOGGLE, - SHORTCUT_HEIGHT_MARKS_ON_LAND_TOGGLE, - SHORTCUT_HEIGHT_MARKS_ON_RIDE_TRACKS_TOGGLE, - SHORTCUT_HEIGHT_MARKS_ON_PATHS_TOGGLE, - SHORTCUT_ADJUST_LAND, - SHORTCUT_ADJUST_WATER, - SHORTCUT_BUILD_SCENERY, - SHORTCUT_BUILD_PATHS, - SHORTCUT_BUILD_NEW_RIDE, - SHORTCUT_SHOW_FINANCIAL_INFORMATION, - SHORTCUT_SHOW_RESEARCH_INFORMATION, - SHORTCUT_SHOW_RIDES_LIST, - SHORTCUT_SHOW_PARK_INFORMATION, - SHORTCUT_SHOW_GUEST_LIST, - SHORTCUT_SHOW_STAFF_LIST, - SHORTCUT_SHOW_RECENT_MESSAGES, - SHORTCUT_SHOW_MAP, - SHORTCUT_SCREENSHOT, - - // New - SHORTCUT_REDUCE_GAME_SPEED, - SHORTCUT_INCREASE_GAME_SPEED, - SHORTCUT_OPEN_CHEAT_WINDOW, - SHORTCUT_REMOVE_TOP_BOTTOM_TOOLBAR_TOGGLE, - SHORTCUT_SCROLL_MAP_UP, - SHORTCUT_SCROLL_MAP_LEFT, - SHORTCUT_SCROLL_MAP_DOWN, - SHORTCUT_SCROLL_MAP_RIGHT, - SHORTCUT_OPEN_CHAT_WINDOW, - SHORTCUT_QUICK_SAVE_GAME, - SHORTCUT_SHOW_OPTIONS, - SHORTCUT_MUTE_SOUND, - SHORTCUT_WINDOWED_MODE_TOGGLE, - SHORTCUT_SHOW_MULTIPLAYER, - SHORTCUT_PAINT_ORIGINAL_TOGGLE, - SHORTCUT_DEBUG_PAINT_TOGGLE, - SHORTCUT_SEE_THROUGH_PATHS_TOGGLE, - - SHORTCUT_COUNT -}; - -enum { - TEMPERATURE_FORMAT_C, - TEMPERATURE_FORMAT_F -}; - -enum { - MEASUREMENT_FORMAT_IMPERIAL, - MEASUREMENT_FORMAT_METRIC, - MEASUREMENT_FORMAT_SI -}; - -enum { - AUTOSAVE_EVERY_MINUTE, - AUTOSAVE_EVERY_5MINUTES, - AUTOSAVE_EVERY_15MINUTES, - AUTOSAVE_EVERY_30MINUTES, - AUTOSAVE_EVERY_HOUR, - AUTOSAVE_NEVER -}; - -enum { - DATE_FORMAT_DMY, - DATE_FORMAT_MDY, - DATE_FORMAT_YMD, - DATE_FORMAT_YDM -}; - -enum { - TITLE_SEQUENCE_RCT1, - TITLE_SEQUENCE_RCT1_AA, - TITLE_SEQUENCE_RCT1_AA_LL, - TITLE_SEQUENCE_RCT2, - TITLE_SEQUENCE_OPENRCT2, - TITLE_SEQUENCE_RANDOM -}; - -enum { - SORT_NAME_ASCENDING, - SORT_NAME_DESCENDING, - SORT_DATE_ASCENDING, - SORT_DATE_DESCENDING, -}; - -enum { - SCENARIO_SELECT_MODE_DIFFICULTY, - SCENARIO_SELECT_MODE_ORIGIN, -}; - -enum { - DRAWING_ENGINE_NONE = -1, - DRAWING_ENGINE_SOFTWARE, - DRAWING_ENGINE_SOFTWARE_WITH_HARDWARE_DISPLAY, - DRAWING_ENGINE_OPENGL, -}; - -typedef struct general_configuration { - uint8 play_intro; - uint8 confirmation_prompt; - uint8 screenshot_format; - utf8string rct1_path; - utf8string rct2_path; - sint8 measurement_format; - sint8 temperature_format; - sint8 currency_format; - sint32 custom_currency_rate; - sint8 custom_currency_affix; - utf8string custom_currency_symbol; - sint8 construction_marker_colour; - sint8 edge_scrolling; - sint8 always_show_gridlines; - sint8 landscape_smoothing; - sint8 show_height_as_units; - sint8 save_plugin_data; - uint8 debugging_tools; - - //new - uint8 fullscreen_mode; - sint32 fullscreen_width; - sint32 fullscreen_height; - sint32 window_width; - sint32 window_height; - uint16 language; - uint8 window_snap_proximity; - uint8 autosave_frequency; - uint8 drawing_engine; - uint8 uncap_fps; - uint8 test_unfinished_tracks; - uint8 no_test_crashes; - uint8 date_format; - uint8 auto_staff_placement; - uint8 handymen_mow_default; - uint8 default_inspection_interval; - utf8string last_run_version; - uint8 invert_viewport_drag; - uint8 load_save_sort; - uint8 minimize_fullscreen_focus_loss; - uint8 day_night_cycle; - uint8 enable_light_fx; - uint8 upper_case_banners; - uint8 disable_lightning_effect; - uint8 allow_loading_with_incorrect_checksum; - uint8 steam_overlay_pause; - float window_scale; - uint8 scale_quality; - uint8 use_nn_at_integer_scales; - uint8 show_fps; - uint8 trap_cursor; - uint8 auto_open_shops; - uint8 scenario_select_mode; - uint8 scenario_unlocking_enabled; - uint8 scenario_hide_mega_park; - utf8string last_save_game_directory; - utf8string last_save_landscape_directory; - utf8string last_save_scenario_directory; - utf8string last_save_track_directory; - uint8 window_limit; - uint8 zoom_to_cursor; - uint8 render_weather_effects; - uint8 render_weather_gloom; -} general_configuration; - -typedef struct interface_configuration { - uint8 toolbar_show_finances; - uint8 toolbar_show_research; - uint8 toolbar_show_cheats; - uint8 toolbar_show_news; - uint8 select_by_track_type; - uint8 console_small_font; - utf8string current_theme_preset; - utf8string current_title_sequence_preset; - uint32 object_selection_filter_flags; -} interface_configuration; - -typedef struct sound_configuration { - uint8 master_volume; - uint8 title_music; - uint8 sound_enabled; - uint8 sound_volume; - uint8 ride_music_enabled; - uint8 ride_music_volume; - uint8 audio_focus; - utf8string device; -} sound_configuration; - -typedef struct twitch_configuration { - utf8string channel; - uint8 enable_follower_peep_names; - uint8 enable_follower_peep_tracking; - uint8 enable_chat_peep_names; - uint8 enable_chat_peep_tracking; - uint8 enable_news; -} twitch_configuration; - -typedef struct network_configuration { - utf8string player_name; - uint32 default_port; - utf8string default_password; - uint8 stay_connected; - uint8 advertise; - uint8 maxplayers; - utf8string server_name; - utf8string server_description; - utf8string server_greeting; - utf8string master_server_url; - utf8string provider_name; - utf8string provider_email; - utf8string provider_website; - uint8 known_keys_only; - uint8 log_chat; -} network_configuration; - -typedef struct notification_configuration { - bool park_award; - bool park_marketing_campaign_finished; - bool park_warnings; - bool park_rating_warnings; - bool ride_broken_down; - bool ride_crashed; - bool ride_warnings; - bool ride_researched; - bool guest_warnings; - bool guest_lost; - bool guest_left_park; - bool guest_queuing_for_ride; - bool guest_on_ride; - bool guest_left_ride; - bool guest_bought_item; - bool guest_used_facility; - bool guest_died; -} notification_configuration; - -typedef struct font_configuration { - utf8string file_name; - utf8string font_name; - sint8 x_offset; - sint8 y_offset; - uint8 size_tiny; - uint8 size_small; - uint8 size_medium; - uint8 size_big; - uint8 height_tiny; - uint8 height_small; - uint8 height_medium; - uint8 height_big; -} font_configuration; - -// Define structures for any other settings here -typedef struct theme_features { - uint8 rct1_ride_lights; - uint8 rct1_park_lights; - uint8 rct1_scenario_font; -} theme_features; - -typedef struct shortcut_entry { - uint8 key; - uint8 modifier; -} shortcut_entry; - -extern general_configuration gConfigGeneral; -extern interface_configuration gConfigInterface; -extern sound_configuration gConfigSound; -extern twitch_configuration gConfigTwitch; -extern network_configuration gConfigNetwork; -extern notification_configuration gConfigNotifications; -extern font_configuration gConfigFonts; - -extern uint16 gShortcutKeys[SHORTCUT_COUNT]; - -void config_get_default_path(utf8 *outPath, size_t size); -void config_set_defaults(); -void config_release(); -bool config_open_default(); -bool config_save_default(); - -uint16 getLanguage(); - -void config_reset_shortcut_keys(); -bool config_shortcut_keys_load(); -bool config_shortcut_keys_save(); - -bool config_find_or_browse_install_directory(); - -void title_sequences_set_default(); -void title_sequences_load_presets(); - -#endif diff --git a/src/openrct2/config/Config.cpp b/src/openrct2/config/Config.cpp new file mode 100644 index 0000000000..753302ad97 --- /dev/null +++ b/src/openrct2/config/Config.cpp @@ -0,0 +1,708 @@ +#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 + +#include +#include "../core/Console.hpp" +#include "../core/Exception.hpp" +#include "../core/FileStream.hpp" +#include "../core/Memory.hpp" +#include "../core/Path.hpp" +#include "../core/String.hpp" +#include "../drawing/IDrawingEngine.h" +#include "../interface/window.h" +#include "../network/network.h" +#include "../OpenRCT2.h" +#include "Config.h" +#include "IniReader.hpp" +#include "IniWriter.hpp" + +extern "C" +{ + #include "../localisation/currency.h" + #include "../localisation/date.h" + #include "../localisation/language.h" + #include "../platform/platform.h" + #include "../scenario/scenario.h" +} + +namespace Config +{ + #pragma region Enums + + static auto Enum_MeasurementFormat = ConfigEnum( + { + ConfigEnumEntry("IMPERIAL", MEASUREMENT_FORMAT_IMPERIAL), + ConfigEnumEntry("METRIC", MEASUREMENT_FORMAT_METRIC), + ConfigEnumEntry("SI", MEASUREMENT_FORMAT_SI), + }); + + static auto Enum_Currency = ConfigEnum( + { + ConfigEnumEntry("GBP", CURRENCY_POUNDS), + ConfigEnumEntry("USD", CURRENCY_DOLLARS), + ConfigEnumEntry("FRF", CURRENCY_FRANC), + ConfigEnumEntry("DEM", CURRENCY_DEUTSCHMARK), + ConfigEnumEntry("JPY", CURRENCY_YEN), + ConfigEnumEntry("ESP", CURRENCY_PESETA), + ConfigEnumEntry("ITL", CURRENCY_LIRA), + ConfigEnumEntry("NLG", CURRENCY_GUILDERS), + ConfigEnumEntry("SEK", CURRENCY_KRONA), + ConfigEnumEntry("EUR", CURRENCY_EUROS), + ConfigEnumEntry("KRW", CURRENCY_WON), + ConfigEnumEntry("RUB", CURRENCY_ROUBLE), + ConfigEnumEntry("CZK", CURRENCY_CZECH_KORUNA), + ConfigEnumEntry("HKD", CURRENCY_HKD), + ConfigEnumEntry("TWD", CURRENCY_TWD), + ConfigEnumEntry("CNY", CURRENCY_YUAN), + }); + + static auto Enum_CurrencySymbolAffix = ConfigEnum( + { + ConfigEnumEntry("PREFIX", CURRENCY_PREFIX), + ConfigEnumEntry("SUFFIX", CURRENCY_SUFFIX), + }); + + static auto Enum_DateFormat = ConfigEnum( + { + ConfigEnumEntry("DD/MM/YY", DATE_FORMAT_DAY_MONTH_YEAR), + ConfigEnumEntry("MM/DD/YY", DATE_FORMAT_MONTH_DAY_YEAR), + ConfigEnumEntry("YY/MM/DD", DATE_FORMAT_YEAR_MONTH_DAY), + ConfigEnumEntry("YY/DD/MM", DATE_FORMAT_YEAR_DAY_MONTH), + }); + + static auto Enum_DrawingEngine = ConfigEnum( + { + ConfigEnumEntry("SOFTWARE", DRAWING_ENGINE_SOFTWARE), + ConfigEnumEntry("SOFTWARE_HWD", DRAWING_ENGINE_SOFTWARE_WITH_HARDWARE_DISPLAY), + ConfigEnumEntry("OPENGL", DRAWING_ENGINE_OPENGL), + }); + + static auto Enum_Temperature = ConfigEnum( + { + ConfigEnumEntry("CELSIUS", TEMPERATURE_FORMAT_C), + ConfigEnumEntry("FAHRENHEIT", TEMPERATURE_FORMAT_F), + }); + + /** + * Config enum wrapping LanguagesDescriptors. + */ + static class LanguageConfigEnum final : public IConfigEnum + { + public: + std::string GetName(sint32 value) const override + { + return LanguagesDescriptors[value].locale; + } + + sint32 GetValue(const std::string &key, sint32 defaultValue) const override + { + sint32 i = 0; + for (const auto &langDesc : LanguagesDescriptors) + { + if (String::Equals(key.c_str(), langDesc.locale)) + { + return i; + } + i++; + } + return defaultValue; + } + } Enum_LanguageEnum; + + #pragma endregion + + static void ReadGeneral(IIniReader * reader) + { + if (reader->ReadSection("general")) + { + auto model = &gConfigGeneral; + model->always_show_gridlines = reader->GetBoolean("always_show_gridlines", false); + model->autosave_frequency = reader->GetSint32("autosave", AUTOSAVE_EVERY_5MINUTES); + model->confirmation_prompt = reader->GetBoolean("confirmation_prompt", false); + model->construction_marker_colour = reader->GetBoolean("construction_marker_colour", false); + model->currency_format = reader->GetEnum("currency_format", CURRENCY_POUNDS, Enum_Currency); + model->custom_currency_rate = reader->GetSint32("custom_currency_rate", 10); + model->custom_currency_affix = reader->GetEnum("custom_currency_affix", CURRENCY_SUFFIX, Enum_CurrencySymbolAffix); + model->custom_currency_symbol = reader->GetCString("custom_currency_symbol", "Ctm"); + model->edge_scrolling = reader->GetBoolean("edge_scrolling", true); + model->fullscreen_mode = reader->GetSint32("fullscreen_mode", 0); + model->fullscreen_height = reader->GetSint32("fullscreen_height", -1); + model->fullscreen_width = reader->GetSint32("fullscreen_width", -1); + model->rct1_path = reader->GetCString("rct1_path", nullptr); + model->rct2_path = reader->GetCString("game_path", nullptr); + model->landscape_smoothing = reader->GetBoolean("landscape_smoothing", true); + model->language = reader->GetEnum("language", LANGUAGE_ENGLISH_UK, Enum_LanguageEnum); + model->measurement_format = reader->GetEnum("measurement_format", MEASUREMENT_FORMAT_METRIC, Enum_MeasurementFormat); + model->play_intro = reader->GetBoolean("play_intro", false); + model->save_plugin_data = reader->GetBoolean("save_plugin_data", true); + model->debugging_tools = reader->GetBoolean("debugging_tools", false); + model->show_height_as_units = reader->GetBoolean("show_height_as_units", false); + model->temperature_format = reader->GetEnum("temperature_format", TEMPERATURE_FORMAT_C, Enum_Temperature); + model->window_height = reader->GetSint32("window_height", -1); + model->window_snap_proximity = reader->GetSint32("window_snap_proximity", 5); + model->window_width = reader->GetSint32("window_width", -1); + model->drawing_engine = reader->GetEnum("drawing_engine", DRAWING_ENGINE_SOFTWARE, Enum_DrawingEngine); + model->uncap_fps = reader->GetBoolean("uncap_fps", false); + + // Default config setting is false until ghost trains are implemented #4540 + model->test_unfinished_tracks = reader->GetBoolean("test_unfinished_tracks", false); + + model->no_test_crashes = reader->GetBoolean("no_test_crashes", false); + model->date_format = reader->GetEnum("date_format", DATE_FORMAT_DAY_MONTH_YEAR, Enum_DateFormat); + model->auto_staff_placement = reader->GetBoolean("auto_staff", true); + model->handymen_mow_default = reader->GetBoolean("handymen_mow_default", false); + model->default_inspection_interval = reader->GetSint32("default_inspection_interval", 2); + model->last_run_version = reader->GetCString("last_run_version", nullptr); + model->invert_viewport_drag = reader->GetBoolean("invert_viewport_drag", false); + model->load_save_sort = reader->GetSint32("load_save_sort", SORT_NAME_ASCENDING); + model->minimize_fullscreen_focus_loss = reader->GetBoolean("minimize_fullscreen_focus_loss", true); + + //Default config setting is false until the games canvas can be seperated from the effect + model->day_night_cycle = reader->GetBoolean("day_night_cycle", false); + + model->enable_light_fx = reader->GetBoolean("enable_light_fx", false); + model->upper_case_banners = reader->GetBoolean("upper_case_banners", false); + model->disable_lightning_effect = reader->GetBoolean("disable_lightning_effect", false); + model->allow_loading_with_incorrect_checksum = reader->GetBoolean("allow_loading_with_incorrect_checksum", true); + model->steam_overlay_pause = reader->GetBoolean("steam_overlay_pause", true); + model->window_scale = reader->GetFloat("window_scale", 1.0f); + model->scale_quality = reader->GetSint32("scale_quality", 1); + model->use_nn_at_integer_scales = reader->GetBoolean("use_nn_at_integer_scales", true); + model->show_fps = reader->GetBoolean("show_fps", false); + model->trap_cursor = reader->GetBoolean("trap_cursor", false); + model->auto_open_shops = reader->GetBoolean("auto_open_shops", false); + model->scenario_select_mode = reader->GetSint32("scenario_select_mode", SCENARIO_SELECT_MODE_ORIGIN); + model->scenario_unlocking_enabled = reader->GetBoolean("scenario_unlocking_enabled", true); + model->scenario_hide_mega_park = reader->GetBoolean("scenario_hide_mega_park", true); + model->last_save_game_directory = reader->GetCString("last_game_directory", nullptr); + model->last_save_landscape_directory = reader->GetCString("last_landscape_directory", nullptr); + model->last_save_scenario_directory = reader->GetCString("last_scenario_directory", nullptr); + model->last_save_track_directory = reader->GetCString("last_track_directory", nullptr); + model->window_limit = reader->GetSint32("window_limit", WINDOW_LIMIT_MAX); + model->zoom_to_cursor = reader->GetBoolean("zoom_to_cursor", true); + model->render_weather_effects = reader->GetBoolean("render_weather_effects", true); + model->render_weather_gloom = reader->GetBoolean("render_weather_gloom", true); + } + } + + static void WriteGeneral(IIniWriter * writer) + { + auto model = &gConfigGeneral; + writer->WriteSection("general"); + writer->WriteBoolean("always_show_gridlines", model->always_show_gridlines); + writer->WriteSint32("autosave", model->autosave_frequency); + writer->WriteBoolean("confirmation_prompt", model->confirmation_prompt); + writer->WriteBoolean("construction_marker_colour", model->construction_marker_colour); + writer->WriteEnum("currency_format", model->currency_format, Enum_Currency); + writer->WriteSint32("custom_currency_rate", model->custom_currency_rate); + writer->WriteEnum("custom_currency_affix", model->custom_currency_affix, Enum_CurrencySymbolAffix); + writer->WriteString("custom_currency_symbol", model->custom_currency_symbol); + writer->WriteBoolean("edge_scrolling", model->edge_scrolling); + writer->WriteSint32("fullscreen_mode", model->fullscreen_mode); + writer->WriteSint32("fullscreen_height", model->fullscreen_height); + writer->WriteSint32("fullscreen_width", model->fullscreen_width); + writer->WriteString("rct1_path", model->rct1_path); + writer->WriteString("game_path", model->rct2_path); + writer->WriteBoolean("landscape_smoothing", model->landscape_smoothing); + writer->WriteEnum("language", model->language, Enum_LanguageEnum); + writer->WriteEnum("measurement_format", model->measurement_format, Enum_MeasurementFormat); + writer->WriteBoolean("play_intro", model->play_intro); + writer->WriteBoolean("save_plugin_data", model->save_plugin_data); + writer->WriteBoolean("debugging_tools", model->debugging_tools); + writer->WriteBoolean("show_height_as_units", model->show_height_as_units); + writer->WriteEnum("temperature_format", model->temperature_format, Enum_Temperature); + writer->WriteSint32("window_height", model->window_height); + writer->WriteSint32("window_snap_proximity", model->window_snap_proximity); + writer->WriteSint32("window_width", model->window_width); + writer->WriteEnum("drawing_engine", model->drawing_engine, Enum_DrawingEngine); + writer->WriteBoolean("uncap_fps", model->uncap_fps); + writer->WriteBoolean("test_unfinished_tracks", model->test_unfinished_tracks); + writer->WriteBoolean("no_test_crashes", model->no_test_crashes); + writer->WriteEnum("date_format", model->date_format, Enum_DateFormat); + writer->WriteBoolean("auto_staff", model->auto_staff_placement); + writer->WriteBoolean("handymen_mow_default", model->handymen_mow_default); + writer->WriteSint32("default_inspection_interval", model->default_inspection_interval); + writer->WriteString("last_run_version", model->last_run_version); + writer->WriteBoolean("invert_viewport_drag", model->invert_viewport_drag); + writer->WriteSint32("load_save_sort", model->load_save_sort); + writer->WriteBoolean("minimize_fullscreen_focus_loss", model->minimize_fullscreen_focus_loss); + writer->WriteBoolean("day_night_cycle", model->day_night_cycle); + writer->WriteBoolean("enable_light_fx", model->enable_light_fx); + writer->WriteBoolean("upper_case_banners", model->upper_case_banners); + writer->WriteBoolean("disable_lightning_effect", model->disable_lightning_effect); + writer->WriteBoolean("allow_loading_with_incorrect_checksum", model->allow_loading_with_incorrect_checksum); + writer->WriteBoolean("steam_overlay_pause", model->steam_overlay_pause); + writer->WriteFloat("window_scale", model->window_scale); + writer->WriteSint32("scale_quality", model->scale_quality); + writer->WriteBoolean("use_nn_at_integer_scales", model->use_nn_at_integer_scales); + writer->WriteBoolean("show_fps", model->show_fps); + writer->WriteBoolean("trap_cursor", model->trap_cursor); + writer->WriteBoolean("auto_open_shops", model->auto_open_shops); + writer->WriteSint32("scenario_select_mode", model->scenario_select_mode); + writer->WriteBoolean("scenario_unlocking_enabled", model->scenario_unlocking_enabled); + writer->WriteBoolean("scenario_hide_mega_park", model->scenario_hide_mega_park); + writer->WriteString("last_game_directory", model->last_save_game_directory); + writer->WriteString("last_landscape_directory", model->last_save_landscape_directory); + writer->WriteString("last_scenario_directory", model->last_save_scenario_directory); + writer->WriteString("last_track_directory", model->last_save_track_directory); + writer->WriteSint32("window_limit", model->window_limit); + writer->WriteBoolean("zoom_to_cursor", model->zoom_to_cursor); + writer->WriteBoolean("render_weather_effects", model->render_weather_effects); + writer->WriteBoolean("render_weather_gloom", model->render_weather_gloom); + } + + static void ReadInterface(IIniReader * reader) + { + if (reader->ReadSection("interface")) + { + auto model = &gConfigInterface; + model->toolbar_show_finances = reader->GetBoolean("toolbar_show_finances", true); + model->toolbar_show_research = reader->GetBoolean("toolbar_show_research", true); + model->toolbar_show_cheats = reader->GetBoolean("toolbar_show_cheats", false); + model->toolbar_show_news = reader->GetBoolean("toolbar_show_news", false); + model->select_by_track_type = reader->GetBoolean("select_by_track_type", false); + model->console_small_font = reader->GetBoolean("console_small_font", false); + model->current_theme_preset = reader->GetCString("current_theme", "*RCT2"); + model->current_title_sequence_preset = reader->GetCString("current_title_sequence", "*OPENRCT2"); + model->object_selection_filter_flags = reader->GetSint32("object_selection_filter_flags", 0x7EF); + } + } + + static void WriteInterface(IIniWriter * writer) + { + auto model = &gConfigInterface; + writer->WriteSection("interface"); + writer->WriteBoolean("toolbar_show_finances", model->toolbar_show_finances); + writer->WriteBoolean("toolbar_show_research", model->toolbar_show_research); + writer->WriteBoolean("toolbar_show_cheats", model->toolbar_show_cheats); + writer->WriteBoolean("toolbar_show_news", model->toolbar_show_news); + writer->WriteBoolean("select_by_track_type", model->select_by_track_type); + writer->WriteBoolean("console_small_font", model->console_small_font); + writer->WriteString("current_theme", model->current_theme_preset); + writer->WriteString("current_title_sequence", model->current_title_sequence_preset); + writer->WriteSint32("object_selection_filter_flags", model->object_selection_filter_flags); + } + + static void ReadSound(IIniReader * reader) + { + if (reader->ReadSection("sound")) + { + auto model = &gConfigSound; + model->master_volume = reader->GetSint32("master_volume", 100); + model->title_music = reader->GetSint32("title_music", 2); + model->sound_enabled = reader->GetBoolean("sound", true); + model->sound_volume = reader->GetSint32("sound_volume", 100); + model->ride_music_enabled = reader->GetBoolean("ride_music", true); + model->ride_music_volume = reader->GetSint32("ride_music_volume", 100); + model->audio_focus = reader->GetBoolean("audio_focus", false); + model->device = reader->GetCString("audio_device", nullptr); + } + } + + static void WriteSound(IIniWriter * writer) + { + auto model = &gConfigSound; + writer->WriteSection("sound"); + writer->WriteSint32("master_volume", model->master_volume); + writer->WriteSint32("title_music", model->title_music); + writer->WriteBoolean("sound", model->sound_enabled); + writer->WriteSint32("sound_volume", model->sound_volume); + writer->WriteBoolean("ride_music", model->ride_music_enabled); + writer->WriteSint32("ride_music_volume", model->ride_music_volume); + writer->WriteBoolean("audio_focus", model->audio_focus); + writer->WriteString("audio_device", model->device); + } + + static void ReadNetwork(IIniReader * reader) + { + if (reader->ReadSection("network")) + { + auto model = &gConfigNetwork; + model->player_name = reader->GetCString("player_name", "Player"); + model->default_port = reader->GetSint32("default_port", NETWORK_DEFAULT_PORT); + model->default_password = reader->GetCString("default_password", nullptr); + model->stay_connected = reader->GetBoolean("stay_connected", true); + model->advertise = reader->GetBoolean("advertise", true); + model->maxplayers = reader->GetSint32("maxplayers", 16); + model->server_name = reader->GetCString("server_name", "Server"); + model->server_description = reader->GetCString("server_description", nullptr); + model->server_greeting = reader->GetCString("server_greeting", nullptr); + model->master_server_url = reader->GetCString("master_server_url", nullptr); + model->provider_name = reader->GetCString("provider_name", nullptr); + model->provider_email = reader->GetCString("provider_email", nullptr); + model->provider_website = reader->GetCString("provider_website", nullptr); + model->known_keys_only = reader->GetBoolean("known_keys_only", false); + model->log_chat = reader->GetBoolean("log_chat", false); + } + } + + static void WriteNetwork(IIniWriter * writer) + { + auto model = &gConfigNetwork; + writer->WriteSection("network"); + writer->WriteString("player_name", model->player_name); + writer->WriteSint32("default_port", model->default_port); + writer->WriteString("default_password", model->default_password); + writer->WriteBoolean("stay_connected", model->stay_connected); + writer->WriteBoolean("advertise", model->advertise); + writer->WriteSint32("maxplayers", model->maxplayers); + writer->WriteString("server_name", model->server_name); + writer->WriteString("server_description", model->server_description); + writer->WriteString("server_greeting", model->server_greeting); + writer->WriteString("master_server_url", model->master_server_url); + writer->WriteString("provider_name", model->provider_name); + writer->WriteString("provider_email", model->provider_email); + writer->WriteString("provider_website", model->provider_website); + writer->WriteBoolean("known_keys_only", model->known_keys_only); + writer->WriteBoolean("log_chat", model->log_chat); + } + + static void ReadNotifications(IIniReader * reader) + { + if (reader->ReadSection("notifications")) + { + auto model = &gConfigNotifications; + model->park_award = reader->GetBoolean("park_award", true); + model->park_marketing_campaign_finished = reader->GetBoolean("park_marketing_campaign_finished", true); + model->park_warnings = reader->GetBoolean("park_warnings", true); + model->park_rating_warnings = reader->GetBoolean("park_rating_warnings", true); + model->ride_broken_down = reader->GetBoolean("ride_broken_down", true); + model->ride_crashed = reader->GetBoolean("ride_crashed", true); + model->ride_warnings = reader->GetBoolean("ride_warnings", true); + model->ride_researched = reader->GetBoolean("ride_researched", true); + model->guest_warnings = reader->GetBoolean("guest_warnings", true); + model->guest_lost = reader->GetBoolean("guest_lost", false); + model->guest_left_park = reader->GetBoolean("guest_entered_left_park", true); + model->guest_queuing_for_ride = reader->GetBoolean("guest_queuing_for_ride", true); + model->guest_on_ride = reader->GetBoolean("guest_on_ride", true); + model->guest_left_ride = reader->GetBoolean("guest_left_ride", true); + model->guest_bought_item = reader->GetBoolean("guest_bought_item", true); + model->guest_used_facility = reader->GetBoolean("guest_used_facility", true); + model->guest_died = reader->GetBoolean("guest_died", true); + } + } + + static void WriteNotifications(IIniWriter * writer) + { + auto model = &gConfigNotifications; + writer->WriteSection("notifications"); + writer->WriteBoolean("park_award", model->park_award); + writer->WriteBoolean("park_marketing_campaign_finished", model->park_marketing_campaign_finished); + writer->WriteBoolean("park_warnings", model->park_warnings); + writer->WriteBoolean("park_rating_warnings", model->park_rating_warnings); + writer->WriteBoolean("ride_broken_down", model->ride_broken_down); + writer->WriteBoolean("ride_crashed", model->ride_crashed); + writer->WriteBoolean("ride_warnings", model->ride_warnings); + writer->WriteBoolean("ride_researched", model->ride_researched); + writer->WriteBoolean("guest_warnings", model->guest_warnings); + writer->WriteBoolean("guest_lost", model->guest_lost); + writer->WriteBoolean("guest_left_park", model->guest_left_park); + writer->WriteBoolean("guest_queuing_for_ride", model->guest_queuing_for_ride); + writer->WriteBoolean("guest_on_ride", model->guest_on_ride); + writer->WriteBoolean("guest_left_ride", model->guest_left_ride); + writer->WriteBoolean("guest_bought_item", model->guest_bought_item); + writer->WriteBoolean("guest_used_facility", model->guest_used_facility); + writer->WriteBoolean("guest_died", model->guest_died); + } + + static void ReadTwitch(IIniReader * reader) + { + if (reader->ReadSection("sound")) + { + auto model = &gConfigTwitch; + model->channel = reader->GetCString("channel", nullptr); + model->enable_follower_peep_names = reader->GetBoolean("follower_peep_names", true); + model->enable_follower_peep_tracking = reader->GetBoolean("follower_peep_tracking", false); + model->enable_chat_peep_names = reader->GetBoolean("chat_peep_names", true); + model->enable_chat_peep_tracking = reader->GetBoolean("chat_peep_tracking", true); + model->enable_news = reader->GetBoolean("news", false); + } + } + + static void WriteTwitch(IIniWriter * writer) + { + auto model = &gConfigTwitch; + writer->WriteSection("twitch"); + writer->WriteString("channel", model->channel); + writer->WriteBoolean("follower_peep_names", model->enable_follower_peep_names); + writer->WriteBoolean("follower_peep_tracking", model->enable_follower_peep_tracking); + writer->WriteBoolean("chat_peep_names", model->enable_chat_peep_names); + writer->WriteBoolean("chat_peep_tracking", model->enable_chat_peep_tracking); + writer->WriteBoolean("news", model->enable_news); + } + + static void ReadFont(IIniReader * reader) + { + if (reader->ReadSection("font")) + { + auto model = &gConfigFonts; + model->file_name = reader->GetCString("file_name", nullptr); + model->font_name = reader->GetCString("font_name", nullptr); + model->x_offset = reader->GetSint32("x_offset", false); + model->y_offset = reader->GetSint32("y_offset", true); + model->size_tiny = reader->GetSint32("size_tiny", true); + model->size_small = reader->GetSint32("size_small", false); + model->size_medium = reader->GetSint32("size_medium", false); + model->size_big = reader->GetSint32("size_big", false); + model->height_tiny = reader->GetSint32("height_tiny", false); + model->height_small = reader->GetSint32("height_small", false); + model->height_medium = reader->GetSint32("height_medium", false); + model->height_big = reader->GetSint32("height_big", false); + } + } + + static void WriteFont(IIniWriter * writer) + { + auto model = &gConfigFonts; + writer->WriteSection("font"); + writer->WriteString("file_name", model->file_name); + writer->WriteString("font_name", model->font_name); + writer->WriteSint32("x_offset", model->x_offset); + writer->WriteSint32("y_offset", model->y_offset); + writer->WriteSint32("size_tiny", model->size_tiny); + writer->WriteSint32("size_small", model->size_small); + writer->WriteSint32("size_medium", model->size_medium); + writer->WriteSint32("size_big", model->size_big); + writer->WriteSint32("height_tiny", model->height_tiny); + writer->WriteSint32("height_small", model->height_small); + writer->WriteSint32("height_medium", model->height_medium); + writer->WriteSint32("height_big", model->height_big); + } + + static bool SetDefaults() + { + try + { + auto reader = std::unique_ptr(CreateDefaultIniReader()); + ReadGeneral(reader.get()); + ReadInterface(reader.get()); + ReadSound(reader.get()); + ReadNetwork(reader.get()); + ReadNotifications(reader.get()); + ReadTwitch(reader.get()); + ReadFont(reader.get()); + return true; + } + catch (const Exception &) + { + return false; + } + } + + static bool ReadFile(const std::string &path) + { + try + { + auto fs = FileStream(path, FILE_MODE_OPEN); + auto reader = std::unique_ptr(CreateIniReader(&fs)); + ReadGeneral(reader.get()); + ReadInterface(reader.get()); + ReadSound(reader.get()); + ReadNetwork(reader.get()); + ReadNotifications(reader.get()); + ReadTwitch(reader.get()); + ReadFont(reader.get()); + return true; + } + catch (const Exception &) + { + return false; + } + } + + static bool WriteFile(const std::string &path) + { + try + { + auto fs = FileStream(path, FILE_MODE_WRITE); + auto writer = std::unique_ptr(CreateIniWriter(&fs)); + WriteGeneral(writer.get()); + WriteInterface(writer.get()); + WriteSound(writer.get()); + WriteNetwork(writer.get()); + WriteNotifications(writer.get()); + WriteTwitch(writer.get()); + WriteFont(writer.get()); + return true; + } + catch (const Exception &ex) + { + Console::WriteLine("Error saving to '%s'", path.c_str()); + Console::WriteLine(ex.GetMessage()); + return false; + } + } + + /** + * Attempts to find the RCT2 installation directory. + * This should be created from some other resource when OpenRCT2 grows. + * @param resultPath Pointer to where the absolute path of the RCT2 installation directory will be copied to. + * @returns 1 if successful, otherwise 0. + */ + static std::string FindRCT2Path() + { + log_verbose("config_find_rct2_path(...)"); + + static const utf8 * searchLocations[] = + { + "C:\\GOG Games\\RollerCoaster Tycoon 2 Triple Thrill Pack", + "C:\\Program Files\\Atari\\RollerCoaster Tycoon 2", + "C:\\Program Files\\GalaxyClient\\Games\\RollerCoaster Tycoon 2 Triple Thrill Pack", + "C:\\Program Files\\Infogrames\\RollerCoaster Tycoon 2", + "C:\\Program Files\\Infogrames Interactive\\RollerCoaster Tycoon 2", + "C:\\Program Files\\Steam\\steamapps\\common\\Rollercoaster Tycoon 2", + "C:\\Program Files (x86)\\Atari\\RollerCoaster Tycoon 2", + "C:\\Program Files (x86)\\GalaxyClient\\Games\\RollerCoaster Tycoon 2 Triple Thrill Pack", + "C:\\Program Files (x86)\\Infogrames\\RollerCoaster Tycoon 2", + "C:\\Program Files (x86)\\Infogrames Interactive\\RollerCoaster Tycoon 2", + "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Rollercoaster Tycoon 2" + }; + + for (const utf8 * location : searchLocations) + { + if (platform_original_game_data_exists(location)) + { + return location; + } + } + if (platform_original_game_data_exists(gExePath)) + { + return gExePath; + } + return std::string(); + } +} + +extern "C" +{ + GeneralConfiguration gConfigGeneral; + InterfaceConfiguration gConfigInterface; + SoundConfiguration gConfigSound; + TwitchConfiguration gConfigTwitch; + NetworkConfiguration gConfigNetwork; + NotificationConfiguration gConfigNotifications; + FontConfiguration gConfigFonts; + + void config_set_defaults() + { + Config::SetDefaults(); + } + + bool config_open(const utf8 * path) + { + return Config::ReadFile(path); + } + + bool config_save(const utf8 * path) + { + return Config::WriteFile(path); + } + + void config_release() + { + SafeFree(gConfigGeneral.rct1_path); + SafeFree(gConfigGeneral.rct2_path); + SafeFree(gConfigGeneral.custom_currency_symbol); + SafeFree(gConfigGeneral.last_save_game_directory); + SafeFree(gConfigGeneral.last_save_landscape_directory); + SafeFree(gConfigGeneral.last_save_scenario_directory); + SafeFree(gConfigGeneral.last_save_track_directory); + SafeFree(gConfigGeneral.last_run_version); + SafeFree(gConfigInterface.current_theme_preset); + SafeFree(gConfigInterface.current_title_sequence_preset); + SafeFree(gConfigSound.device); + SafeFree(gConfigTwitch.channel); + SafeFree(gConfigNetwork.player_name); + SafeFree(gConfigNetwork.default_password); + SafeFree(gConfigNetwork.server_name); + SafeFree(gConfigNetwork.server_description); + SafeFree(gConfigNetwork.server_greeting); + SafeFree(gConfigNetwork.master_server_url); + SafeFree(gConfigNetwork.provider_name); + SafeFree(gConfigNetwork.provider_email); + SafeFree(gConfigNetwork.provider_website); + SafeFree(gConfigFonts.file_name); + SafeFree(gConfigFonts.font_name); + } + + void config_get_default_path(utf8 * outPath, size_t size) + { + platform_get_user_directory(outPath, nullptr, size); + Path::Append(outPath, size, "config.ini"); + } + + bool config_open_default() + { + utf8 path[MAX_PATH]; + config_get_default_path(path, sizeof(path)); + if (config_open(path)) + { + currency_load_custom_currency_config(); + return true; + } + return false; + } + + bool config_save_default() + { + utf8 path[MAX_PATH]; + config_get_default_path(path, sizeof(path)); + if (config_save(path)) + { + return true; + } + return false; + } + + bool config_find_or_browse_install_directory() + { + std::string path = Config::FindRCT2Path(); + if (!path.empty()) + { + Memory::Free(gConfigGeneral.rct2_path); + gConfigGeneral.rct2_path = String::Duplicate(path.c_str()); + } + else + { + if (gOpenRCT2Headless) + { + return false; + } + while (1) + { + platform_show_messagebox("OpenRCT2 needs files from the original RollerCoaster Tycoon 2 in order to work. Please select the directory where you installed RollerCoaster Tycoon 2."); + utf8 * installPath = platform_open_directory_browser("Please select your RCT2 directory"); + if (installPath == nullptr) + { + return false; + } + + Memory::Free(gConfigGeneral.rct2_path); + gConfigGeneral.rct2_path = installPath; + + if (platform_original_game_data_exists(installPath)) + { + return true; + } + + utf8 message[MAX_PATH]; + snprintf(message, MAX_PATH, "Could not find %s" PATH_SEPARATOR "Data" PATH_SEPARATOR "g1.dat at this path", installPath); + platform_show_messagebox(message); + } + } + return true; + } +} diff --git a/src/openrct2/config/Config.h b/src/openrct2/config/Config.h new file mode 100644 index 0000000000..d8f812666a --- /dev/null +++ b/src/openrct2/config/Config.h @@ -0,0 +1,233 @@ +#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 once + +#include "../common.h" + +typedef struct GeneralConfiguration +{ + // Paths + utf8 * rct1_path; + utf8 * rct2_path; + + // Display + sint32 window_width; + sint32 window_height; + sint32 fullscreen_mode; + sint32 fullscreen_width; + sint32 fullscreen_height; + float window_scale; + sint32 drawing_engine; + sint32 scale_quality; + bool use_nn_at_integer_scales; + bool uncap_fps; + bool show_fps; + bool minimize_fullscreen_focus_loss; + + // Map rendering + bool landscape_smoothing; + bool always_show_gridlines; + bool construction_marker_colour; + bool day_night_cycle; + bool enable_light_fx; + bool upper_case_banners; + bool render_weather_effects; + bool render_weather_gloom; + bool disable_lightning_effect; + + // Localisation + sint32 language; + sint32 measurement_format; + sint32 temperature_format; + bool show_height_as_units; + sint32 date_format; + sint32 currency_format; + sint32 custom_currency_rate; + sint32 custom_currency_affix; + utf8 * custom_currency_symbol; + + // Controls + bool edge_scrolling; + bool trap_cursor; + bool invert_viewport_drag; + bool zoom_to_cursor; + + // Miscellaneous + bool play_intro; + sint32 window_snap_proximity; + bool allow_loading_with_incorrect_checksum; + bool save_plugin_data; + bool test_unfinished_tracks; + bool no_test_crashes; + bool debugging_tools; + sint32 autosave_frequency; + bool auto_staff_placement; + bool handymen_mow_default; + bool auto_open_shops; + sint32 default_inspection_interval; + sint32 window_limit; + sint32 scenario_select_mode; + bool scenario_unlocking_enabled; + bool scenario_hide_mega_park; + bool steam_overlay_pause; + + bool confirmation_prompt; + sint32 load_save_sort; + utf8 * last_save_game_directory; + utf8 * last_save_landscape_directory; + utf8 * last_save_scenario_directory; + utf8 * last_save_track_directory; + utf8 * last_run_version; + + sint32 screenshot_format; +} GeneralConfiguration; + +typedef struct InterfaceConfiguration +{ + bool toolbar_show_finances; + bool toolbar_show_research; + bool toolbar_show_cheats; + bool toolbar_show_news; + bool select_by_track_type; + bool console_small_font; + utf8 * current_theme_preset; + utf8 * current_title_sequence_preset; + sint32 object_selection_filter_flags; +} InterfaceConfiguration; + +typedef struct SoundConfiguration +{ + utf8 * device; + uint8 master_volume; + uint8 title_music; + bool sound_enabled; + uint8 sound_volume; + bool ride_music_enabled; + uint8 ride_music_volume; + bool audio_focus; +} SoundConfiguration; + +typedef struct TwitchConfiguration +{ + utf8 * channel; + bool enable_follower_peep_names; + bool enable_follower_peep_tracking; + bool enable_chat_peep_names; + bool enable_chat_peep_tracking; + bool enable_news; +} TwitchConfiguration; + +typedef struct NetworkConfiguration +{ + utf8 * player_name; + sint32 default_port; + utf8 * default_password; + bool stay_connected; + bool advertise; + sint32 maxplayers; + utf8 * server_name; + utf8 * server_description; + utf8 * server_greeting; + utf8 * master_server_url; + utf8 * provider_name; + utf8 * provider_email; + utf8 * provider_website; + bool known_keys_only; + bool log_chat; +} NetworkConfiguration; + +typedef struct NotificationConfiguration +{ + bool park_award; + bool park_marketing_campaign_finished; + bool park_warnings; + bool park_rating_warnings; + bool ride_broken_down; + bool ride_crashed; + bool ride_warnings; + bool ride_researched; + bool guest_warnings; + bool guest_lost; + bool guest_left_park; + bool guest_queuing_for_ride; + bool guest_on_ride; + bool guest_left_ride; + bool guest_bought_item; + bool guest_used_facility; + bool guest_died; +} NotificationConfiguration; + +typedef struct FontConfiguration +{ + utf8 * file_name; + utf8 * font_name; + sint32 x_offset; + sint32 y_offset; + sint32 size_tiny; + sint32 size_small; + sint32 size_medium; + sint32 size_big; + sint32 height_tiny; + sint32 height_small; + sint32 height_medium; + sint32 height_big; +} FontConfiguration; + +enum SORT +{ + SORT_NAME_ASCENDING, + SORT_NAME_DESCENDING, + SORT_DATE_ASCENDING, + SORT_DATE_DESCENDING, +}; + +enum TEMPERATURE_FORMAT +{ + TEMPERATURE_FORMAT_C, + TEMPERATURE_FORMAT_F +}; + +enum MEASUREMENT_FORMAT +{ + MEASUREMENT_FORMAT_IMPERIAL, + MEASUREMENT_FORMAT_METRIC, + MEASUREMENT_FORMAT_SI +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + extern GeneralConfiguration gConfigGeneral; + extern InterfaceConfiguration gConfigInterface; + extern SoundConfiguration gConfigSound; + extern TwitchConfiguration gConfigTwitch; + extern NetworkConfiguration gConfigNetwork; + extern NotificationConfiguration gConfigNotifications; + extern FontConfiguration gConfigFonts; + + bool config_open(const utf8 * path); + bool config_save(const utf8 * path); + void config_get_default_path(utf8 *outPath, size_t size); + void config_set_defaults(); + void config_release(); + bool config_open_default(); + bool config_save_default(); + bool config_find_or_browse_install_directory(); +#ifdef __cplusplus +} +#endif diff --git a/src/openrct2/config/ConfigEnum.hpp b/src/openrct2/config/ConfigEnum.hpp new file mode 100644 index 0000000000..b29769f785 --- /dev/null +++ b/src/openrct2/config/ConfigEnum.hpp @@ -0,0 +1,79 @@ +#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 once + +#include +#include +#include "../core/String.hpp" + +template +struct ConfigEnumEntry +{ + std::string Key; + T Value; + + ConfigEnumEntry(const std::string &key, T value) + : Key(key), + Value(value) + { + } +}; + +template +interface IConfigEnum +{ + virtual ~IConfigEnum() = default; + virtual std::string GetName(T value) const abstract; + virtual T GetValue(const std::string &key, T defaultValue) const abstract; +}; + +template +class ConfigEnum final : public IConfigEnum +{ +private: + std::vector> _entries; + +public: + ConfigEnum(std::initializer_list> entries) + { + _entries = entries; + } + + std::string GetName(T value) const override + { + for (const auto &entry : _entries) + { + if (entry.Value == value) + { + return entry.Key; + } + } + return std::string(); + } + + T GetValue(const std::string &key, T defaultValue) const override + { + for (const auto &entry : _entries) + { + if (String::Equals(entry.Key, key, true)) + { + return entry.Value; + } + } + return defaultValue; + } +}; diff --git a/src/openrct2/config/IniReader.cpp b/src/openrct2/config/IniReader.cpp new file mode 100644 index 0000000000..4f0e67ed9c --- /dev/null +++ b/src/openrct2/config/IniReader.cpp @@ -0,0 +1,396 @@ +#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 + +#include +#include +#include +#include +#include +#include "../common.h" +#include "../core/FileStream.hpp" +#include "../core/String.hpp" +#include "../core/StringBuilder.hpp" +#include "IniReader.hpp" + +/** + * Simple tuple (start, length) representing a text span in a buffer. + */ +struct Span +{ + size_t Start = 0; + size_t Length = 0; + + Span() = default; + Span(size_t start, size_t length) + : Start(start), + Length(length) + { + } +}; + +/** + * Simple tuple (start, end) inclusive representing a range of lines. + */ +struct LineRange +{ + size_t Start = 0; + size_t End = 0; + + LineRange() = default; + LineRange(size_t start, size_t end) + : Start(start), + End(end) + { + } +}; + +class IniReader final : public IIniReader +{ +private: + std::vector _buffer; + std::vector _lines; + std::unordered_map _sections; + std::unordered_map _values; + +public: + IniReader(IStream * stream) + { + uint64 length = stream->GetLength() - stream->GetPosition(); + _buffer.resize(length); + stream->Read(_buffer.data(), length); + + RemoveBOM(); + + // Ensure there is a null terminator on the end, this is + // mainly for ParseLines's sake + if (_buffer.empty() || _buffer[length - 1] != 0) + { + _buffer.push_back(0); + } + + ParseLines(); + ParseSections(); + } + + bool ReadSection(const std::string &name) override + { + auto it = _sections.find(name); + if (it == _sections.end()) + { + return false; + } + + ParseSectionValues(it->second); + return true; + } + + bool GetBoolean(const std::string &name, bool defaultValue) const override + { + bool result = defaultValue; + std::string value; + if (TryGetString(name, &value)) + { + result = String::Equals(value, "true", true); + } + return result; + } + + sint32 GetSint32(const std::string &name, sint32 defaultValue) const override + { + sint32 result = defaultValue; + std::string value; + if (TryGetString(name, &value)) + { + try + { + result = std::stoi(value); + } + catch (std::exception) + { + } + } + return result; + } + + float GetFloat(const std::string &name, float defaultValue) const override + { + float result = defaultValue; + std::string value; + if (TryGetString(name, &value)) + { + try + { + result = std::stof(value); + } + catch (std::exception) + { + } + } + return result; + } + + std::string GetString(const std::string &name, const std::string &defaultValue) const override + { + std::string result; + if (!TryGetString(name, &result)) + { + result = defaultValue; + } + return result; + } + + bool TryGetString(const std::string &name, std::string * outValue) const override + { + auto it = _values.find(name); + if (it == _values.end()) + { + return false; + } + + *outValue = it->second; + return true; + } + +private: + void RemoveBOM() + { + if (_buffer.size() < 3) + { + return; + } + utf8 * file = (utf8 *)_buffer.data(); + utf8 * content = String::SkipBOM(file); + if (file != content) + { + size_t skipLength = content - file; + _buffer.erase(_buffer.begin(), _buffer.begin() + skipLength); + } + } + + void ParseLines() + { + size_t lineBegin = 0; + bool onNewLineCh = false; + for (size_t i = 0; i < _buffer.size(); i++) + { + char b = (char)_buffer[i]; + if (b == 0 || b == '\n' || b == '\r') + { + if (!onNewLineCh) + { + onNewLineCh = true; + size_t lineEnd = i; + _lines.emplace_back(lineBegin, lineEnd - lineBegin); + } + } + else if (onNewLineCh) + { + onNewLineCh = false; + lineBegin = i; + } + } + } + + void ParseSections() + { + std::string sectionName; + LineRange lineRange; + + for (size_t i = 0; i < _lines.size(); i++) + { + std::string line = GetLine(i); + line = String::Trim(line); + if (line.size() > 3 && line[0] == '[') + { + size_t endIndex = line.find_first_of(']'); + if (endIndex != std::string::npos) + { + // Add last section + if (!sectionName.empty()) + { + lineRange.End = i - 1; + _sections[sectionName] = lineRange; + } + + // Set up new section + sectionName = line.substr(1, endIndex - 1); + lineRange.Start = i; + } + } + } + + // Add final section + if (!sectionName.empty()) + { + lineRange.End = _lines.size() - 1; + _sections[sectionName] = lineRange; + } + } + + void ParseSectionValues(LineRange range) + { + for (size_t i = range.Start + 1; i <= range.End; i++) + { + ParseValue(i); + } + } + + void ParseValue(size_t lineIndex) + { + std::string line = GetLine(lineIndex); + line = TrimComment(line); + + // Find assignment character + size_t equalsIndex = line.find_first_of('='); + if (equalsIndex == std::string::npos) + { + return; + } + + // Get the key and value + std::string key = String::Trim(line.substr(0, equalsIndex)); + std::string value = String::Trim(line.substr(equalsIndex + 1)); + + value = UnquoteValue(value); + value = UnescapeValue(value); + _values[key] = value; + } + + std::string TrimComment(const std::string &s) + { + char inQuotes = 0; + bool escaped = false; + for (size_t i = 0; i < s.size(); i++) + { + char c = s[i]; + if (inQuotes == 0 && c == '#' && !escaped) + { + return s.substr(0, i); + } + else if (c == inQuotes && !escaped) + { + inQuotes = 0; + } + else if ((c == '\'' || c == '"') && !escaped) + { + inQuotes = c; + } + escaped = (c == '\\' && !escaped); + } + return s; + } + + std::string UnquoteValue(const std::string &s) + { + std::string result = s; + size_t length = s.size(); + if (length >= 2) + { + if ((s[0] == '"' || s[0] == '\'') && s[0] == s[length - 1]) + { + result = s.substr(1, length - 2); + } + } + return result; + } + + std::string UnescapeValue(const std::string &s) + { + if (s.find_first_of('\\') == std::string::npos) + { + return s; + } + + bool escaped = false; + auto sb = StringBuilder(); + for (char c : s) + { + if (c == '\\' && !escaped) + { + escaped = true; + } + else + { + escaped = false; + sb.Append(&c, 1); + } + } + return std::string(sb.GetString()); + } + + std::string GetLine(size_t index) + { + utf8 * szBuffer = (utf8 *)_buffer.data(); + auto span = _lines[index]; + auto line = std::string(szBuffer + span.Start, span.Length); + return line; + } +}; + +class DefaultIniReader final : public IIniReader +{ +public: + bool ReadSection(const std::string &name) override + { + return true; + } + + bool GetBoolean(const std::string &name, bool defaultValue) const override + { + return defaultValue; + } + + sint32 GetSint32(const std::string &name, sint32 defaultValue) const override + { + return defaultValue; + } + + float GetFloat(const std::string &name, float defaultValue) const override + { + return defaultValue; + } + + std::string GetString(const std::string &name, const std::string &defaultValue) const override + { + return defaultValue; + } + + bool TryGetString(const std::string &name, std::string * outValue) const override + { + return false; + } +}; + +utf8 * IIniReader::GetCString(const std::string &name, const utf8 * defaultValue) const +{ + std::string szValue; + if (!TryGetString(name, &szValue)) + { + return String::Duplicate(defaultValue); + } + + return String::Duplicate(szValue.c_str()); +} + +IIniReader * CreateIniReader(IStream * stream) +{ + return new IniReader(stream); +} + +IIniReader * CreateDefaultIniReader() +{ + return new DefaultIniReader(); +} diff --git a/src/openrct2/config/IniReader.hpp b/src/openrct2/config/IniReader.hpp new file mode 100644 index 0000000000..e5fee1c671 --- /dev/null +++ b/src/openrct2/config/IniReader.hpp @@ -0,0 +1,51 @@ +#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 + +#include +#include "../common.h" +#include "ConfigEnum.hpp" + +interface IStream; + +interface IIniReader +{ + virtual ~IIniReader() = default; + + virtual bool ReadSection(const std::string &name) abstract; + + virtual bool GetBoolean(const std::string &name, bool defaultValue) const abstract; + virtual sint32 GetSint32(const std::string &name, sint32 defaultValue) const abstract; + virtual float GetFloat(const std::string &name, float defaultValue) const abstract; + virtual std::string GetString(const std::string &name, const std::string &defaultValue) const abstract; + virtual bool TryGetString(const std::string &name, std::string * outValue) const abstract; + + template + T GetEnum(const std::string &name, T defaultValue, const IConfigEnum &configEnum) const + { + std::string szValue; + if (!TryGetString(name, &szValue)) + { + return defaultValue; + } + + return configEnum.GetValue(szValue, defaultValue); + } + + utf8 * GetCString(const std::string &name, const utf8 * defaultValue) const; +}; + +IIniReader * CreateIniReader(IStream * stream); +IIniReader * CreateDefaultIniReader(); diff --git a/src/openrct2/config/IniWriter.cpp b/src/openrct2/config/IniWriter.cpp new file mode 100644 index 0000000000..e846018ed3 --- /dev/null +++ b/src/openrct2/config/IniWriter.cpp @@ -0,0 +1,108 @@ +#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 + +#include +#include "../core/FileStream.hpp" +#include "../platform/platform.h" +#include "IniWriter.hpp" + +class IniWriter final : public IIniWriter +{ +private: + IStream * _stream; + bool _firstSection = true; + +public: + IniWriter(IStream * stream) + : _stream(stream) + { + } + + void WriteSection(const std::string &name) override + { + if (!_firstSection) + { + WriteLine(); + } + _firstSection = false; + + WriteLine("[" + name + "]"); + } + + void WriteBoolean(const std::string &name, bool value) override + { + WriteProperty(name, value ? "true" : "false"); + } + + void WriteSint32(const std::string &name, sint32 value) override + { + WriteProperty(name, std::to_string(value)); + } + + void WriteFloat(const std::string &name, float value) override + { + WriteProperty(name, std::to_string(value)); + } + + void WriteString(const std::string &name, const std::string &value) override + { + std::ostringstream buffer; + buffer << '"'; + for (char c : value) + { + if (c == '\\' || c == '"') + { + buffer << '\\'; + } + buffer << c; + } + buffer << '"'; + + WriteProperty(name, buffer.str()); + } + + void WriteEnum(const std::string &name, const std::string &key) override + { + WriteProperty(name, key); + } + +private: + void WriteProperty(const std::string &name, const std::string &value) + { + WriteLine(name + " = " + value); + } + + void WriteLine() + { + _stream->Write(PLATFORM_NEWLINE, String::SizeOf(PLATFORM_NEWLINE)); + } + + void WriteLine(const std::string &line) + { + _stream->Write(line.c_str(), line.size()); + WriteLine(); + } +}; + +void IIniWriter::WriteString(const std::string &name, const utf8 * value) +{ + WriteString(name, String::ToStd(value)); +} + +IIniWriter * CreateIniWriter(IStream * stream) +{ + return new IniWriter(stream); +} diff --git a/src/openrct2/config/IniWriter.hpp b/src/openrct2/config/IniWriter.hpp new file mode 100644 index 0000000000..434d710116 --- /dev/null +++ b/src/openrct2/config/IniWriter.hpp @@ -0,0 +1,52 @@ +#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 + +#include +#include "../common.h" +#include "ConfigEnum.hpp" + +interface IStream; + +interface IIniWriter +{ + virtual ~IIniWriter() = default; + + virtual void WriteSection(const std::string &name) abstract; + + virtual void WriteBoolean(const std::string &name, bool value) abstract; + virtual void WriteSint32(const std::string &name, sint32 value) abstract; + virtual void WriteFloat(const std::string &name, float value) abstract; + virtual void WriteString(const std::string &name, const std::string &value) abstract; + virtual void WriteEnum(const std::string &name, const std::string &key) abstract; + + template + void WriteEnum(const std::string &name, T value, const IConfigEnum &configEnum) + { + std::string key = configEnum.GetName(value); + if (key.empty()) + { + WriteSint32(name, value); + } + else + { + WriteEnum(name, key); + } + } + + void WriteString(const std::string &name, const utf8 * value); +}; + +IIniWriter * CreateIniWriter(IStream * stream); diff --git a/src/openrct2/config/KeyboardShortcuts.cpp b/src/openrct2/config/KeyboardShortcuts.cpp new file mode 100644 index 0000000000..765f46b337 --- /dev/null +++ b/src/openrct2/config/KeyboardShortcuts.cpp @@ -0,0 +1,162 @@ +#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 + +#include "../common.h" +#include "../core/Console.hpp" +#include "../core/FileStream.hpp" +#include "../core/Memory.hpp" +#include "../core/Path.hpp" +#include "../core/String.hpp" + +extern "C" +{ + #include "../interface/keyboard_shortcut.h" + #include "../platform/platform.h" +} + +// Current keyboard shortcuts +uint16 gShortcutKeys[SHORTCUT_COUNT]; + +namespace KeyboardShortcuts +{ + // Default keyboard shortcuts + static const uint16 _defaultShortcutKeys[SHORTCUT_COUNT] = + { + SDL_SCANCODE_BACKSPACE, // SHORTCUT_CLOSE_TOP_MOST_WINDOW + SHIFT | SDL_SCANCODE_BACKSPACE, // SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS + SDL_SCANCODE_ESCAPE, // SHORTCUT_CANCEL_CONSTRUCTION_MODE + SDL_SCANCODE_PAUSE, // SHORTCUT_PAUSE_GAME + SDL_SCANCODE_PAGEUP, // SHORTCUT_ZOOM_VIEW_OUT + SDL_SCANCODE_PAGEDOWN, // SHORTCUT_ZOOM_VIEW_IN + SDL_SCANCODE_RETURN, // SHORTCUT_ROTATE_VIEW_CLOCKWISE + SHIFT | SDL_SCANCODE_RETURN, // SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE + SDL_SCANCODE_Z, // SHORTCUT_ROTATE_CONSTRUCTION_OBJECT + SDL_SCANCODE_1, // SHORTCUT_UNDERGROUND_VIEW_TOGGLE + SDL_SCANCODE_H, // SHORTCUT_REMOVE_BASE_LAND_TOGGLE + SDL_SCANCODE_V, // SHORTCUT_REMOVE_VERTICAL_LAND_TOGGLE + SDL_SCANCODE_3, // SHORTCUT_SEE_THROUGH_RIDES_TOGGLE + SDL_SCANCODE_4, // SHORTCUT_SEE_THROUGH_SCENERY_TOGGLE + SDL_SCANCODE_5, // SHORTCUT_INVISIBLE_SUPPORTS_TOGGLE + SDL_SCANCODE_6, // SHORTCUT_INVISIBLE_PEOPLE_TOGGLE + SDL_SCANCODE_8, // SHORTCUT_HEIGHT_MARKS_ON_LAND_TOGGLE + SDL_SCANCODE_9, // SHORTCUT_HEIGHT_MARKS_ON_RIDE_TRACKS_TOGGLE + SDL_SCANCODE_0, // SHORTCUT_HEIGHT_MARKS_ON_PATHS_TOGGLE + SDL_SCANCODE_F1, // SHORTCUT_ADJUST_LAND + SDL_SCANCODE_F2, // SHORTCUT_ADJUST_WATER + SDL_SCANCODE_F3, // SHORTCUT_BUILD_SCENERY + SDL_SCANCODE_F4, // SHORTCUT_BUILD_PATHS + SDL_SCANCODE_F5, // SHORTCUT_BUILD_NEW_RIDE + SDL_SCANCODE_F, // SHORTCUT_SHOW_FINANCIAL_INFORMATION + SDL_SCANCODE_D, // SHORTCUT_SHOW_RESEARCH_INFORMATION + SDL_SCANCODE_R, // SHORTCUT_SHOW_RIDES_LIST + SDL_SCANCODE_P, // SHORTCUT_SHOW_PARK_INFORMATION + SDL_SCANCODE_G, // SHORTCUT_SHOW_GUEST_LIST + SDL_SCANCODE_S, // SHORTCUT_SHOW_STAFF_LIST + SDL_SCANCODE_M, // SHORTCUT_SHOW_RECENT_MESSAGES + SDL_SCANCODE_TAB, // SHORTCUT_SHOW_MAP + PLATFORM_MODIFIER | SDL_SCANCODE_S, // SHORTCUT_SCREENSHOT + SDL_SCANCODE_MINUS, // SHORTCUT_REDUCE_GAME_SPEED, + SDL_SCANCODE_EQUALS, // SHORTCUT_INCREASE_GAME_SPEED, + PLATFORM_MODIFIER | ALT | SDL_SCANCODE_C, // SHORTCUT_OPEN_CHEAT_WINDOW, + SDL_SCANCODE_T, // SHORTCUT_REMOVE_TOP_BOTTOM_TOOLBAR_TOGGLE, + SDL_SCANCODE_UP, // SHORTCUT_SCROLL_MAP_UP + SDL_SCANCODE_LEFT, // SHORTCUT_SCROLL_MAP_LEFT + SDL_SCANCODE_DOWN, // SHORTCUT_SCROLL_MAP_DOWN + SDL_SCANCODE_RIGHT, // SHORTCUT_SCROLL_MAP_RIGHT + SDL_SCANCODE_C, // SHORTCUT_OPEN_CHAT_WINDOW + PLATFORM_MODIFIER | SDL_SCANCODE_F10, // SHORTCUT_QUICK_SAVE_GAME + SHORTCUT_UNDEFINED, // SHORTCUT_SHOW_OPTIONS + SHORTCUT_UNDEFINED, // SHORTCUT_MUTE_SOUND + ALT | SDL_SCANCODE_RETURN, // SHORTCUT_WINDOWED_MODE_TOGGLE + SHORTCUT_UNDEFINED, // SHORTCUT_SHOW_MULTIPLAYER + SHORTCUT_UNDEFINED, // SHORTCUT_PAINT_ORIGINAL_TOGGLE + SHORTCUT_UNDEFINED, // SHORTCUT_DEBUG_PAINT_TOGGLE + SHORTCUT_UNDEFINED, // SHORTCUT_SEE_THROUGH_PATHS_TOGGLE + }; + + constexpr sint32 CURRENT_FILE_VERSION = 1; + + static void Reset() + { + Memory::Copy(gShortcutKeys, _defaultShortcutKeys, sizeof(gShortcutKeys)); + } + + static std::string GetPath() + { + utf8 path[MAX_PATH]; + platform_get_user_directory(path, nullptr, sizeof(path)); + Path::Append(path, sizeof(path), "hotkeys.cfg"); + return path; + } +} + +extern "C" +{ + void config_reset_shortcut_keys() + { + KeyboardShortcuts::Reset(); + } + + bool config_shortcut_keys_load() + { + bool result = false; + try + { + std::string path = KeyboardShortcuts::GetPath(); + auto fs = FileStream(path, FILE_MODE_OPEN); + + uint16 version = fs.ReadValue(); + if (version == KeyboardShortcuts::CURRENT_FILE_VERSION) + { + for (sint32 i = 0; i < SHORTCUT_COUNT; i++) + { + gShortcutKeys[i] = fs.ReadValue(); + } + result = true; + } + else + { + result = false; + } + } + catch (const Exception &ex) + { + Console::WriteLine("Error reading shortcut keys: %s", ex.GetMessage()); + } + return result; + } + + bool config_shortcut_keys_save() + { + bool result = false; + try + { + std::string path = KeyboardShortcuts::GetPath(); + auto fs = FileStream(path, FILE_MODE_WRITE); + fs.WriteValue(KeyboardShortcuts::CURRENT_FILE_VERSION); + for (sint32 i = 0; i < SHORTCUT_COUNT; i++) + { + fs.WriteValue(gShortcutKeys[i]); + } + result = true; + } + catch (const Exception &ex) + { + Console::WriteLine("Error writing shortcut keys: %s", ex.GetMessage()); + } + return result; + } +} diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index 68c9ad85ba..5f3fafd435 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -393,4 +393,35 @@ namespace String { return String::Set(buffer, bufferSize, TrimStart(src)); } + + std::string Trim(const std::string &s) + { + codepoint_t codepoint; + const utf8 * ch = s.c_str(); + const utf8 * nextCh; + const utf8 * startSubstr = nullptr; + const utf8 * endSubstr = nullptr; + while ((codepoint = GetNextCodepoint(ch, &nextCh)) != '\0') + { + bool isWhiteSpace = codepoint <= WCHAR_MAX && iswspace((wchar_t)codepoint); + if (!isWhiteSpace) + { + if (startSubstr == nullptr) + { + startSubstr = ch; + } + endSubstr = ch; + } + ch = nextCh; + } + + if (startSubstr == nullptr) + { + // String is all whitespace + return std::string(); + } + + size_t stringLength = endSubstr - startSubstr + 1; + return std::string(startSubstr, stringLength); + } } diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index 287c1c3cd0..427374b2af 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -75,4 +75,5 @@ namespace String utf8 * Trim(utf8 * str); const utf8 * TrimStart(const utf8 * str); utf8 * TrimStart(utf8 * buffer, size_t bufferSize, const utf8 * src); + std::string Trim(const std::string &s); } diff --git a/src/openrct2/drawing/IDrawingEngine.h b/src/openrct2/drawing/IDrawingEngine.h index a4ded3b623..a9e7287201 100644 --- a/src/openrct2/drawing/IDrawingEngine.h +++ b/src/openrct2/drawing/IDrawingEngine.h @@ -20,8 +20,13 @@ #include -struct rct_drawpixelinfo; -interface IDrawingContext; +enum DRAWING_ENGINE +{ + DRAWING_ENGINE_NONE = -1, + DRAWING_ENGINE_SOFTWARE, + DRAWING_ENGINE_SOFTWARE_WITH_HARDWARE_DISPLAY, + DRAWING_ENGINE_OPENGL, +}; enum DRAWING_ENGINE_FLAGS { @@ -33,6 +38,11 @@ enum DRAWING_ENGINE_FLAGS DEF_DIRTY_OPTIMISATIONS = 1 << 0, }; +#ifdef __cplusplus + +struct rct_drawpixelinfo; +interface IDrawingContext; + interface IDrawingEngine { virtual ~IDrawingEngine() { } @@ -73,3 +83,5 @@ interface IRainDrawer sint32 xStart, sint32 yStart) abstract; }; + +#endif diff --git a/src/openrct2/drawing/NewDrawing.cpp b/src/openrct2/drawing/NewDrawing.cpp index 1b91c5dcca..5e2b479ad8 100644 --- a/src/openrct2/drawing/NewDrawing.cpp +++ b/src/openrct2/drawing/NewDrawing.cpp @@ -21,7 +21,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../drawing/drawing.h" #include "../interface/screenshot.h" #include "../localisation/string_ids.h" diff --git a/src/openrct2/drawing/Rain.cpp b/src/openrct2/drawing/Rain.cpp index b73e64ed43..5cf27f7ef7 100644 --- a/src/openrct2/drawing/Rain.cpp +++ b/src/openrct2/drawing/Rain.cpp @@ -19,7 +19,7 @@ extern "C" #include "../interface/window.h" #include "../world/climate.h" #include "drawing.h" - #include "../config.h" + #include "../config/Config.h" } #include "IDrawingEngine.h" diff --git a/src/openrct2/drawing/engines/SoftwareDrawingEngine.cpp b/src/openrct2/drawing/engines/SoftwareDrawingEngine.cpp index a1a6a14f8e..87ab3a7459 100644 --- a/src/openrct2/drawing/engines/SoftwareDrawingEngine.cpp +++ b/src/openrct2/drawing/engines/SoftwareDrawingEngine.cpp @@ -23,7 +23,7 @@ extern "C" { - #include "../../config.h" + #include "../../config/Config.h" #include "../../game.h" #include "../../interface/screenshot.h" #include "../../interface/viewport.h" diff --git a/src/openrct2/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/openrct2/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 725f484428..e870cf540b 100644 --- a/src/openrct2/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/openrct2/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -47,11 +47,11 @@ IDrawingEngine * DrawingEngineFactory::CreateOpenGL() #include "../../IDrawingContext.h" #include "../../IDrawingEngine.h" #include "../../Rain.h" -#include "../../../config.h" +#include "../../../config/Config.h" extern "C" { - #include "../../../config.h" + #include "../../../config/Config.h" #include "../../../interface/screenshot.h" #include "../../../interface/window.h" #include "../../../intro.h" diff --git a/src/openrct2/drawing/lightfx.h b/src/openrct2/drawing/lightfx.h index d61b79a1d6..1d59bbfa12 100644 --- a/src/openrct2/drawing/lightfx.h +++ b/src/openrct2/drawing/lightfx.h @@ -19,6 +19,7 @@ #ifdef __ENABLE_LIGHTFX__ +#include #include "../common.h" #include "drawing.h" diff --git a/src/openrct2/drawing/scrolling_text.c b/src/openrct2/drawing/scrolling_text.c index 3334f6f2cb..746b8fd6ad 100644 --- a/src/openrct2/drawing/scrolling_text.c +++ b/src/openrct2/drawing/scrolling_text.c @@ -15,7 +15,7 @@ #pragma endregion #include "../rct2/addresses.h" -#include "../config.h" +#include "../config/Config.h" #include "../interface/colour.h" #include "../localisation/localisation.h" #include "../sprites.h" diff --git a/src/openrct2/drawing/sprite.cpp b/src/openrct2/drawing/sprite.cpp index 1a27f690dc..f58c1752ad 100644 --- a/src/openrct2/drawing/sprite.cpp +++ b/src/openrct2/drawing/sprite.cpp @@ -24,7 +24,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../rct2/addresses.h" #include "../util/util.h" #include "drawing.h" diff --git a/src/openrct2/drawing/string.c b/src/openrct2/drawing/string.c index 7733a39ca6..621897b7f3 100644 --- a/src/openrct2/drawing/string.c +++ b/src/openrct2/drawing/string.c @@ -17,6 +17,7 @@ #include "../interface/colour.h" #include "../interface/viewport.h" #include "../localisation/localisation.h" +#include "../platform/platform.h" #include "../sprites.h" #include "../util/util.h" diff --git a/src/openrct2/game.c b/src/openrct2/game.c index 43fa7e97a1..f42a5771b9 100644 --- a/src/openrct2/game.c +++ b/src/openrct2/game.c @@ -16,7 +16,7 @@ #include "audio/audio.h" #include "cheats.h" -#include "config.h" +#include "config/Config.h" #include "editor.h" #include "game.h" #include "input.h" diff --git a/src/openrct2/input.c b/src/openrct2/input.c index 39284a33b7..7c693b92d5 100644 --- a/src/openrct2/input.c +++ b/src/openrct2/input.c @@ -16,7 +16,7 @@ #include #include "audio/audio.h" -#include "config.h" +#include "config/Config.h" #include "game.h" #include "input.h" #include "interface/chat.h" diff --git a/src/openrct2/interface/Fonts.cpp b/src/openrct2/interface/Fonts.cpp index 66fad11583..ca6d759703 100644 --- a/src/openrct2/interface/Fonts.cpp +++ b/src/openrct2/interface/Fonts.cpp @@ -21,7 +21,7 @@ #include "Fonts.h" extern "C" { -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" #include "../localisation/language.h" } diff --git a/src/openrct2/interface/Theme.cpp b/src/openrct2/interface/Theme.cpp index 4c419ce5f8..ff0cb0fc86 100644 --- a/src/openrct2/interface/Theme.cpp +++ b/src/openrct2/interface/Theme.cpp @@ -22,7 +22,8 @@ extern "C" { #include "../common.h" - #include "../config.h" + #include "../config/Config.h" + #include "../platform/platform.h" #include "themes.h" #include "window.h" } diff --git a/src/openrct2/interface/console.c b/src/openrct2/interface/console.c index db70738d75..73022728f1 100644 --- a/src/openrct2/interface/console.c +++ b/src/openrct2/interface/console.c @@ -17,7 +17,7 @@ #include #include -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" #include "../game.h" #include "../input.h" diff --git a/src/openrct2/interface/keyboard_shortcut.c b/src/openrct2/interface/keyboard_shortcut.c index 23d21021b1..ff561361bb 100644 --- a/src/openrct2/interface/keyboard_shortcut.c +++ b/src/openrct2/interface/keyboard_shortcut.c @@ -15,7 +15,7 @@ #pragma endregion #include "../audio/audio.h" -#include "../config.h" +#include "../config/Config.h" #include "../editor.h" #include "../game.h" #include "../input.h" diff --git a/src/openrct2/interface/keyboard_shortcut.h b/src/openrct2/interface/keyboard_shortcut.h index 9e2c8fefc5..29bf930c8f 100644 --- a/src/openrct2/interface/keyboard_shortcut.h +++ b/src/openrct2/interface/keyboard_shortcut.h @@ -29,4 +29,72 @@ void keyboard_shortcut_handle(sint32 key); void keyboard_shortcut_handle_command(sint32 shortcutIndex); void keyboard_shortcut_format_string(char *buffer, size_t size, uint16 shortcutKey); +void config_reset_shortcut_keys(); +bool config_shortcut_keys_load(); +bool config_shortcut_keys_save(); + +typedef struct shortcut_entry { + uint8 key; + uint8 modifier; +} shortcut_entry; + +enum { + SHORTCUT_CLOSE_TOP_MOST_WINDOW, + SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS, + SHORTCUT_CANCEL_CONSTRUCTION_MODE, + SHORTCUT_PAUSE_GAME, + SHORTCUT_ZOOM_VIEW_OUT, + SHORTCUT_ZOOM_VIEW_IN, + SHORTCUT_ROTATE_VIEW_CLOCKWISE, + SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE, + SHORTCUT_ROTATE_CONSTRUCTION_OBJECT, + SHORTCUT_UNDERGROUND_VIEW_TOGGLE, + SHORTCUT_REMOVE_BASE_LAND_TOGGLE, + SHORTCUT_REMOVE_VERTICAL_LAND_TOGGLE, + SHORTCUT_SEE_THROUGH_RIDES_TOGGLE, + SHORTCUT_SEE_THROUGH_SCENERY_TOGGLE, + SHORTCUT_INVISIBLE_SUPPORTS_TOGGLE, + SHORTCUT_INVISIBLE_PEOPLE_TOGGLE, + SHORTCUT_HEIGHT_MARKS_ON_LAND_TOGGLE, + SHORTCUT_HEIGHT_MARKS_ON_RIDE_TRACKS_TOGGLE, + SHORTCUT_HEIGHT_MARKS_ON_PATHS_TOGGLE, + SHORTCUT_ADJUST_LAND, + SHORTCUT_ADJUST_WATER, + SHORTCUT_BUILD_SCENERY, + SHORTCUT_BUILD_PATHS, + SHORTCUT_BUILD_NEW_RIDE, + SHORTCUT_SHOW_FINANCIAL_INFORMATION, + SHORTCUT_SHOW_RESEARCH_INFORMATION, + SHORTCUT_SHOW_RIDES_LIST, + SHORTCUT_SHOW_PARK_INFORMATION, + SHORTCUT_SHOW_GUEST_LIST, + SHORTCUT_SHOW_STAFF_LIST, + SHORTCUT_SHOW_RECENT_MESSAGES, + SHORTCUT_SHOW_MAP, + SHORTCUT_SCREENSHOT, + + // New + SHORTCUT_REDUCE_GAME_SPEED, + SHORTCUT_INCREASE_GAME_SPEED, + SHORTCUT_OPEN_CHEAT_WINDOW, + SHORTCUT_REMOVE_TOP_BOTTOM_TOOLBAR_TOGGLE, + SHORTCUT_SCROLL_MAP_UP, + SHORTCUT_SCROLL_MAP_LEFT, + SHORTCUT_SCROLL_MAP_DOWN, + SHORTCUT_SCROLL_MAP_RIGHT, + SHORTCUT_OPEN_CHAT_WINDOW, + SHORTCUT_QUICK_SAVE_GAME, + SHORTCUT_SHOW_OPTIONS, + SHORTCUT_MUTE_SOUND, + SHORTCUT_WINDOWED_MODE_TOGGLE, + SHORTCUT_SHOW_MULTIPLAYER, + SHORTCUT_PAINT_ORIGINAL_TOGGLE, + SHORTCUT_DEBUG_PAINT_TOGGLE, + SHORTCUT_SEE_THROUGH_PATHS_TOGGLE, + + SHORTCUT_COUNT +}; + +extern uint16 gShortcutKeys[SHORTCUT_COUNT]; + #endif diff --git a/src/openrct2/interface/screenshot.c b/src/openrct2/interface/screenshot.c index 86a3f6af82..af45a9c394 100644 --- a/src/openrct2/interface/screenshot.c +++ b/src/openrct2/interface/screenshot.c @@ -15,7 +15,7 @@ #pragma endregion #include "../audio/audio.h" -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" #include "../game.h" #include "../Imaging.h" diff --git a/src/openrct2/interface/viewport.c b/src/openrct2/interface/viewport.c index c48b043186..5dbe953783 100644 --- a/src/openrct2/interface/viewport.c +++ b/src/openrct2/interface/viewport.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" #include "../game.h" #include "../input.h" diff --git a/src/openrct2/interface/window.c b/src/openrct2/interface/window.c index 39eec54670..6bcf417546 100644 --- a/src/openrct2/interface/window.c +++ b/src/openrct2/interface/window.c @@ -29,7 +29,7 @@ #include "viewport.h" #include "widget.h" #include "window.h" -#include "../config.h" +#include "../config/Config.h" #define RCT2_FIRST_WINDOW (g_window_list) #define RCT2_LAST_WINDOW (gWindowNextSlot - 1) diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 601b403f64..1ae212c74d 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -72,6 +72,10 @@ + + + + @@ -88,7 +92,6 @@ - @@ -419,6 +422,10 @@ + + + + @@ -433,7 +440,6 @@ - diff --git a/src/openrct2/localisation/currency.c b/src/openrct2/localisation/currency.c index aa570ebc23..2081cb2085 100644 --- a/src/openrct2/localisation/currency.c +++ b/src/openrct2/localisation/currency.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../util/util.h" #include "currency.h" #include "string_ids.h" diff --git a/src/openrct2/localisation/localisation.c b/src/openrct2/localisation/localisation.c index 6abd04d044..3bfb088cbb 100644 --- a/src/openrct2/localisation/localisation.c +++ b/src/openrct2/localisation/localisation.c @@ -23,7 +23,7 @@ #include #endif // __WINDOWS__ -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../util/util.h" #include "date.h" diff --git a/src/openrct2/management/award.c b/src/openrct2/management/award.c index df0b6982ed..f434d6e6d7 100644 --- a/src/openrct2/management/award.c +++ b/src/openrct2/management/award.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../interface/window.h" #include "../localisation/localisation.h" #include "../peep/peep.h" diff --git a/src/openrct2/management/marketing.c b/src/openrct2/management/marketing.c index 3c0de6ff2d..0bcad0cb14 100644 --- a/src/openrct2/management/marketing.c +++ b/src/openrct2/management/marketing.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/window.h" #include "../localisation/localisation.h" diff --git a/src/openrct2/management/research.c b/src/openrct2/management/research.c index e27835eb8e..8adf4d9d56 100644 --- a/src/openrct2/management/research.c +++ b/src/openrct2/management/research.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/window.h" #include "../localisation/date.h" diff --git a/src/openrct2/network/NetworkServerAdvertiser.cpp b/src/openrct2/network/NetworkServerAdvertiser.cpp index 194c108019..13b02df084 100644 --- a/src/openrct2/network/NetworkServerAdvertiser.cpp +++ b/src/openrct2/network/NetworkServerAdvertiser.cpp @@ -25,7 +25,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../localisation/date.h" #include "../management/finance.h" #include "../peep/peep.h" diff --git a/src/openrct2/network/network.cpp b/src/openrct2/network/network.cpp index a00758fc2c..da85257082 100644 --- a/src/openrct2/network/network.cpp +++ b/src/openrct2/network/network.cpp @@ -51,7 +51,7 @@ sint32 _pickup_peep_old_x = SPRITE_LOCATION_NULL; #include "../rct2/S6Exporter.h" extern "C" { -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/chat.h" #include "../interface/window.h" @@ -1629,7 +1629,7 @@ void Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& p } } - if (gConfigNetwork.maxplayers <= player_list.size()) { + if ((size_t)gConfigNetwork.maxplayers <= player_list.size()) { connection.AuthStatus = NETWORK_AUTH_FULL; } else if (connection.AuthStatus == NETWORK_AUTH_VERIFIED) { diff --git a/src/openrct2/network/twitch.cpp b/src/openrct2/network/twitch.cpp index 3ddf3e5a4a..7290a1640a 100644 --- a/src/openrct2/network/twitch.cpp +++ b/src/openrct2/network/twitch.cpp @@ -35,7 +35,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../drawing/drawing.h" #include "../game.h" #include "../interface/console.h" diff --git a/src/openrct2/object/ObjectRepository.cpp b/src/openrct2/object/ObjectRepository.cpp index a089805fce..9ffe6f038b 100644 --- a/src/openrct2/object/ObjectRepository.cpp +++ b/src/openrct2/object/ObjectRepository.cpp @@ -43,7 +43,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../localisation/localisation.h" #include "../object.h" #include "../object_list.h" diff --git a/src/openrct2/object/RideObject.cpp b/src/openrct2/object/RideObject.cpp index b1034c008c..476e452b76 100644 --- a/src/openrct2/object/RideObject.cpp +++ b/src/openrct2/object/RideObject.cpp @@ -23,7 +23,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../drawing/drawing.h" #include "../localisation/localisation.h" #include "../rct1.h" diff --git a/src/openrct2/paint/map_element/banner.c b/src/openrct2/paint/map_element/banner.c index 73dcc271aa..ccfcd33af9 100644 --- a/src/openrct2/paint/map_element/banner.c +++ b/src/openrct2/paint/map_element/banner.c @@ -15,7 +15,7 @@ #pragma endregion #include "../paint.h" -#include "../../config.h" +#include "../../config/Config.h" #include "../../game.h" #include "../../interface/viewport.h" #include "../../localisation/localisation.h" diff --git a/src/openrct2/paint/map_element/entrance.c b/src/openrct2/paint/map_element/entrance.c index 19d7156275..9f24b28ff2 100644 --- a/src/openrct2/paint/map_element/entrance.c +++ b/src/openrct2/paint/map_element/entrance.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../../config.h" +#include "../../config/Config.h" #include "../../game.h" #include "../../interface/viewport.h" #include "../../localisation/localisation.h" diff --git a/src/openrct2/paint/map_element/fence.c b/src/openrct2/paint/map_element/fence.c index e7f8a1dc1d..362b97c96e 100644 --- a/src/openrct2/paint/map_element/fence.c +++ b/src/openrct2/paint/map_element/fence.c @@ -20,7 +20,7 @@ #include "../../world/scenery.h" #include "../../game.h" #include "../../ride/track.h" -#include "../../config.h" +#include "../../config/Config.h" #include "../../localisation/localisation.h" #include "../../interface/colour.h" #include "../../interface/viewport.h" diff --git a/src/openrct2/paint/map_element/map_element.c b/src/openrct2/paint/map_element/map_element.c index 1b0e748d1e..652e2acbab 100644 --- a/src/openrct2/paint/map_element/map_element.c +++ b/src/openrct2/paint/map_element/map_element.c @@ -21,7 +21,7 @@ #include "../../ride/ride_data.h" #include "../../ride/track_data.h" #include "../../ride/track_paint.h" -#include "../../config.h" +#include "../../config/Config.h" #include "../../world/sprite.h" #include "../../world/banner.h" #include "../../world/entrance.h" diff --git a/src/openrct2/paint/map_element/path.c b/src/openrct2/paint/map_element/path.c index 89e8c5038c..c2aeab96ed 100644 --- a/src/openrct2/paint/map_element/path.c +++ b/src/openrct2/paint/map_element/path.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../../config.h" +#include "../../config/Config.h" #include "../../game.h" #include "../../interface/viewport.h" #include "../../localisation/localisation.h" diff --git a/src/openrct2/paint/map_element/scenery.c b/src/openrct2/paint/map_element/scenery.c index a6ba6c7304..165821a3ee 100644 --- a/src/openrct2/paint/map_element/scenery.c +++ b/src/openrct2/paint/map_element/scenery.c @@ -15,7 +15,7 @@ #pragma endregion #include "map_element.h" -#include "../../config.h" +#include "../../config/Config.h" #include "../../game.h" #include "../../interface/viewport.h" #include "../../localisation/date.h" diff --git a/src/openrct2/paint/map_element/scenery_multiple.c b/src/openrct2/paint/map_element/scenery_multiple.c index c0e9b64ec3..2f83176796 100644 --- a/src/openrct2/paint/map_element/scenery_multiple.c +++ b/src/openrct2/paint/map_element/scenery_multiple.c @@ -17,7 +17,7 @@ #include "map_element.h" #include "../paint.h" #include "../supports.h" -#include "../../config.h" +#include "../../config/Config.h" #include "../../game.h" #include "../../interface/viewport.h" #include "../../localisation/localisation.h" diff --git a/src/openrct2/paint/map_element/surface.c b/src/openrct2/paint/map_element/surface.c index 1b430f5807..5e422fdc12 100644 --- a/src/openrct2/paint/map_element/surface.c +++ b/src/openrct2/paint/map_element/surface.c @@ -15,7 +15,7 @@ #pragma endregion #include "../../cheats.h" -#include "../../config.h" +#include "../../config/Config.h" #include "../../interface/viewport.h" #include "../../peep/staff.h" #include "../../rct2.h" diff --git a/src/openrct2/paint/paint.c b/src/openrct2/paint/paint.c index 95121d63ca..c426510142 100644 --- a/src/openrct2/paint/paint.c +++ b/src/openrct2/paint/paint.c @@ -17,7 +17,7 @@ #include "paint.h" #include "../drawing/drawing.h" #include "../localisation/localisation.h" -#include "../config.h" +#include "../config/Config.h" #include "../interface/viewport.h" #include "map_element/map_element.h" #include "sprite/sprite.h" diff --git a/src/openrct2/paint/sprite/peep.c b/src/openrct2/paint/sprite/peep.c index 2baec97009..78629cb7b7 100644 --- a/src/openrct2/paint/sprite/peep.c +++ b/src/openrct2/paint/sprite/peep.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../../config.h" +#include "../../config/Config.h" #include "../../drawing/lightfx.h" #include "../../interface/viewport.h" #include "../../paint/sprite/sprite.h" diff --git a/src/openrct2/peep/peep.c b/src/openrct2/peep/peep.c index aeef199b52..015e93bd90 100644 --- a/src/openrct2/peep/peep.c +++ b/src/openrct2/peep/peep.c @@ -17,7 +17,7 @@ #include "../audio/audio.h" #include "../audio/AudioMixer.h" #include "../cheats.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../input.h" #include "../interface/window.h" diff --git a/src/openrct2/peep/staff.c b/src/openrct2/peep/staff.c index d197541e21..fffb4c932e 100644 --- a/src/openrct2/peep/staff.c +++ b/src/openrct2/peep/staff.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/viewport.h" #include "../localisation/date.h" diff --git a/src/openrct2/platform/linux.c b/src/openrct2/platform/linux.c index 4805814fc3..79bb4c1bb3 100644 --- a/src/openrct2/platform/linux.c +++ b/src/openrct2/platform/linux.c @@ -33,7 +33,7 @@ #include #include -#include "../config.h" +#include "../config/Config.h" #include "../localisation/language.h" #include "../localisation/string_ids.h" #include "../util/util.h" @@ -461,7 +461,7 @@ bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc, return 1; } -utf8 *platform_open_directory_browser(utf8 *title) { +utf8 *platform_open_directory_browser(const utf8 *title) { size_t size; dialog_type dtype; sint32 exit_value; diff --git a/src/openrct2/platform/macos.m b/src/openrct2/platform/macos.m index 77b67b8808..87116b6e70 100644 --- a/src/openrct2/platform/macos.m +++ b/src/openrct2/platform/macos.m @@ -22,7 +22,7 @@ #include "platform.h" #include "../util/util.h" #include "../localisation/language.h" -#include "../config.h" +#include "../config/Config.h" bool platform_check_steam_overlay_attached() { STUB(); @@ -105,7 +105,7 @@ void platform_show_messagebox(const char * message) } } -utf8 *platform_open_directory_browser(utf8 *title) +utf8 *platform_open_directory_browser(const utf8 *title) { @autoreleasepool { diff --git a/src/openrct2/platform/platform.h b/src/openrct2/platform/platform.h index 29a81740b7..df2181f2c5 100644 --- a/src/openrct2/platform/platform.h +++ b/src/openrct2/platform/platform.h @@ -195,7 +195,7 @@ void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory, size_t utf8* platform_get_username(); void platform_show_messagebox(const utf8 * message); bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc, size_t outSize); -utf8 *platform_open_directory_browser(utf8 *title); +utf8 *platform_open_directory_browser(const utf8 *title); uint8 platform_get_locale_currency(); uint8 platform_get_currency_value(const char *currencyCode); uint16 platform_get_locale_language(); diff --git a/src/openrct2/platform/posix.c b/src/openrct2/platform/posix.c index e3c1a14a0c..10edddbf22 100644 --- a/src/openrct2/platform/posix.c +++ b/src/openrct2/platform/posix.c @@ -26,7 +26,7 @@ #include #include #include -#include "../config.h" +#include "../config/Config.h" #include "../localisation/language.h" #include "../OpenRCT2.h" #include "../util/util.h" diff --git a/src/openrct2/platform/shared.c b/src/openrct2/platform/shared.c index 69167de298..85904494fe 100644 --- a/src/openrct2/platform/shared.c +++ b/src/openrct2/platform/shared.c @@ -16,8 +16,9 @@ #include "../audio/audio.h" #include "../audio/AudioMixer.h" -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" +#include "../drawing/IDrawingEngine.h" #include "../drawing/lightfx.h" #include "../editor.h" #include "../game.h" diff --git a/src/openrct2/platform/windows.c b/src/openrct2/platform/windows.c index d7b4f944fe..fa568c323d 100644 --- a/src/openrct2/platform/windows.c +++ b/src/openrct2/platform/windows.c @@ -31,7 +31,7 @@ #include #include -#include "../config.h" +#include "../config/Config.h" #include "../localisation/language.h" #include "../OpenRCT2.h" #include "../util/util.h" @@ -694,7 +694,7 @@ bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc, return result; } -utf8 *platform_open_directory_browser(utf8 *title) +utf8 *platform_open_directory_browser(const utf8 *title) { BROWSEINFOW bi; wchar_t pszBuffer[MAX_PATH], wctitle[256]; diff --git a/src/openrct2/rct1.c b/src/openrct2/rct1.c index 087dbfc049..8fc3ec223f 100644 --- a/src/openrct2/rct1.c +++ b/src/openrct2/rct1.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "config.h" +#include "config/Config.h" #include "game.h" #include "localisation/string_ids.h" #include "rct1.h" diff --git a/src/openrct2/rct2.c b/src/openrct2/rct2.c index 0d060e2f1f..193b190f7f 100644 --- a/src/openrct2/rct2.c +++ b/src/openrct2/rct2.c @@ -19,7 +19,7 @@ #include #include "audio/audio.h" #include "audio/AudioMixer.h" -#include "config.h" +#include "config/Config.h" #include "drawing/drawing.h" #include "drawing/lightfx.h" #include "editor.h" @@ -27,6 +27,7 @@ #include "input.h" #include "interface/chat.h" #include "interface/console.h" +#include "interface/keyboard_shortcut.h" #include "interface/viewport.h" #include "intro.h" #include "localisation/date.h" diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index 4b021e594c..3a9e2c5d6a 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -27,7 +27,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../game.h" #include "../interface/viewport.h" #include "../interface/window.h" diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index f235c4bb1e..63ab974b46 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -29,7 +29,7 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../game.h" #include "../interface/viewport.h" #include "../localisation/date.h" diff --git a/src/openrct2/ride/gentle/mini_golf.c b/src/openrct2/ride/gentle/mini_golf.c index 85d097e713..fe4f327247 100644 --- a/src/openrct2/ride/gentle/mini_golf.c +++ b/src/openrct2/ride/gentle/mini_golf.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../../config.h" +#include "../../config/Config.h" #include "../../interface/viewport.h" #include "../../paint/paint.h" #include "../../paint/supports.h" diff --git a/src/openrct2/ride/ride.c b/src/openrct2/ride/ride.c index 4232eba460..b921ce9ddb 100644 --- a/src/openrct2/ride/ride.c +++ b/src/openrct2/ride/ride.c @@ -18,7 +18,7 @@ #include "../audio/AudioMixer.h" #include "../cheats.h" #include "../common.h" -#include "../config.h" +#include "../config/Config.h" #include "../editor.h" #include "../game.h" #include "../input.h" diff --git a/src/openrct2/ride/thrill/launched_freefall.c b/src/openrct2/ride/thrill/launched_freefall.c index 9d05dc9e5f..0afca53064 100644 --- a/src/openrct2/ride/thrill/launched_freefall.c +++ b/src/openrct2/ride/thrill/launched_freefall.c @@ -15,7 +15,7 @@ #pragma endregion #include "../../common.h" -#include "../../config.h" +#include "../../config/Config.h" #include "../../interface/viewport.h" #include "../../world/sprite.h" #include "../../paint/paint.h" diff --git a/src/openrct2/ride/track.c b/src/openrct2/ride/track.c index 855a2a4bff..cfb7df9cfb 100644 --- a/src/openrct2/ride/track.c +++ b/src/openrct2/ride/track.c @@ -16,7 +16,7 @@ #include "../audio/audio.h" #include "../cheats.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/viewport.h" #include "../localisation/localisation.h" diff --git a/src/openrct2/ride/track_design_save.c b/src/openrct2/ride/track_design_save.c index 0066e2b4a0..504c801b21 100644 --- a/src/openrct2/ride/track_design_save.c +++ b/src/openrct2/ride/track_design_save.c @@ -15,7 +15,7 @@ #pragma endregion #include "../audio/audio.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../localisation/localisation.h" #include "../localisation/string_ids.h" diff --git a/src/openrct2/ride/track_paint.c b/src/openrct2/ride/track_paint.c index d157556aad..be45d6b807 100644 --- a/src/openrct2/ride/track_paint.c +++ b/src/openrct2/ride/track_paint.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" #include "../paint/supports.h" #include "../interface/viewport.h" diff --git a/src/openrct2/ride/vehicle.c b/src/openrct2/ride/vehicle.c index 2e416ef552..eff9c268f5 100644 --- a/src/openrct2/ride/vehicle.c +++ b/src/openrct2/ride/vehicle.c @@ -16,7 +16,7 @@ #include "../audio/audio.h" #include "../audio/AudioMixer.h" -#include "../config.h" +#include "../config/Config.h" #include "../editor.h" #include "../game.h" #include "../interface/viewport.h" diff --git a/src/openrct2/ride/water/river_rapids.c b/src/openrct2/ride/water/river_rapids.c index cd43bec882..61ec7d4bd3 100644 --- a/src/openrct2/ride/water/river_rapids.c +++ b/src/openrct2/ride/water/river_rapids.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../../config.h" +#include "../../config/Config.h" #include "../../interface/viewport.h" #include "../../world/sprite.h" #include "../../paint/paint.h" diff --git a/src/openrct2/ride/water/splash_boats.c b/src/openrct2/ride/water/splash_boats.c index 06c4715c6a..06942a85c2 100644 --- a/src/openrct2/ride/water/splash_boats.c +++ b/src/openrct2/ride/water/splash_boats.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../../config.h" +#include "../../config/Config.h" #include "../../interface/viewport.h" #include "../../paint/paint.h" #include "../../paint/supports.h" diff --git a/src/openrct2/scenario/ScenarioRepository.cpp b/src/openrct2/scenario/ScenarioRepository.cpp index a060df524e..0b13a013ef 100644 --- a/src/openrct2/scenario/ScenarioRepository.cpp +++ b/src/openrct2/scenario/ScenarioRepository.cpp @@ -32,8 +32,9 @@ extern "C" { - #include "../config.h" + #include "../config/Config.h" #include "../localisation/localisation.h" + #include "../platform/platform.h" #include "../rct2.h" #include "scenario.h" } diff --git a/src/openrct2/scenario/scenario.c b/src/openrct2/scenario/scenario.c index b439ee333d..867b29db1b 100644 --- a/src/openrct2/scenario/scenario.c +++ b/src/openrct2/scenario/scenario.c @@ -16,7 +16,7 @@ #include "../audio/audio.h" #include "../cheats.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/viewport.h" #include "../localisation/date.h" diff --git a/src/openrct2/scenario/scenario.h b/src/openrct2/scenario/scenario.h index 468d1d82d0..3ca8a91945 100644 --- a/src/openrct2/scenario/scenario.h +++ b/src/openrct2/scenario/scenario.h @@ -21,7 +21,6 @@ #include "../management/finance.h" #include "../management/research.h" #include "../object.h" -#include "../platform/platform.h" #include "../rct12.h" #include "../rct2.h" #include "../rct2/addresses.h" @@ -343,6 +342,20 @@ enum { OBJECTIVE_MONTHLY_FOOD_INCOME }; +enum { + SCENARIO_SELECT_MODE_DIFFICULTY, + SCENARIO_SELECT_MODE_ORIGIN, +}; + +enum { + AUTOSAVE_EVERY_MINUTE, + AUTOSAVE_EVERY_5MINUTES, + AUTOSAVE_EVERY_15MINUTES, + AUTOSAVE_EVERY_30MINUTES, + AUTOSAVE_EVERY_HOUR, + AUTOSAVE_NEVER +}; + #define AUTOSAVE_PAUSE 0 extern const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT]; @@ -368,7 +381,7 @@ extern rct_s6_info gS6Info; extern char gScenarioName[64]; extern char gScenarioDetails[256]; extern char gScenarioCompletedBy[32]; -extern char gScenarioSavePath[MAX_PATH]; +extern char gScenarioSavePath[260]; extern char gScenarioExpansionPacks[3256]; extern sint32 gFirstTimeSave; extern uint16 gSavedAge; diff --git a/src/openrct2/title/TitleScreen.cpp b/src/openrct2/title/TitleScreen.cpp index 9bda6890ea..24d02fdcbc 100644 --- a/src/openrct2/title/TitleScreen.cpp +++ b/src/openrct2/title/TitleScreen.cpp @@ -26,7 +26,7 @@ extern "C" { #include "../audio/audio.h" - #include "../config.h" + #include "../config/Config.h" #include "../drawing/drawing.h" #include "../game.h" #include "../input.h" diff --git a/src/openrct2/windows/banner.c b/src/openrct2/windows/banner.c index ac1c58894b..fb3517368a 100644 --- a/src/openrct2/windows/banner.c +++ b/src/openrct2/windows/banner.c @@ -15,7 +15,7 @@ #pragma endregion #include "../game.h" -#include "../config.h" +#include "../config/Config.h" #include "../localisation/localisation.h" #include "../interface/viewport.h" #include "../interface/widget.h" diff --git a/src/openrct2/windows/cheats.c b/src/openrct2/windows/cheats.c index c28ea386e9..d6b166fbea 100644 --- a/src/openrct2/windows/cheats.c +++ b/src/openrct2/windows/cheats.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/widget.h" #include "../interface/window.h" diff --git a/src/openrct2/windows/custom_currency.c b/src/openrct2/windows/custom_currency.c index e5085076cf..f4d1b923f7 100644 --- a/src/openrct2/windows/custom_currency.c +++ b/src/openrct2/windows/custom_currency.c @@ -18,7 +18,7 @@ * 'Custom currency configuration' window definition and logic. */ -#include "../config.h" +#include "../config/Config.h" #include "../localisation/localisation.h" #include "../interface/widget.h" #include "../interface/window.h" diff --git a/src/openrct2/windows/editor_bottom_toolbar.c b/src/openrct2/windows/editor_bottom_toolbar.c index 4cade3a608..d484d7b531 100644 --- a/src/openrct2/windows/editor_bottom_toolbar.c +++ b/src/openrct2/windows/editor_bottom_toolbar.c @@ -15,7 +15,7 @@ #pragma endregion #include "../audio/audio.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../editor.h" #include "../input.h" diff --git a/src/openrct2/windows/editor_object_selection.c b/src/openrct2/windows/editor_object_selection.c index 932fdd8dd1..8adbbb90fe 100644 --- a/src/openrct2/windows/editor_object_selection.c +++ b/src/openrct2/windows/editor_object_selection.c @@ -17,7 +17,7 @@ #pragma warning(disable : 4295) // 'identifier': array is too small to include a terminating null character #include "../audio/audio.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../editor.h" #include "../interface/themes.h" diff --git a/src/openrct2/windows/error.c b/src/openrct2/windows/error.c index 85f03c308b..fe72033904 100644 --- a/src/openrct2/windows/error.c +++ b/src/openrct2/windows/error.c @@ -15,9 +15,10 @@ #pragma endregion #include "../audio/audio.h" -#include "../localisation/localisation.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../platform/platform.h" #include "../rct2.h" #include "error.h" diff --git a/src/openrct2/windows/finances.c b/src/openrct2/windows/finances.c index 61a6a52419..10bb3d9430 100644 --- a/src/openrct2/windows/finances.c +++ b/src/openrct2/windows/finances.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/graph.h" #include "../interface/widget.h" diff --git a/src/openrct2/windows/game_bottom_toolbar.c b/src/openrct2/windows/game_bottom_toolbar.c index 9b2a1e6ae0..e91d8dff2b 100644 --- a/src/openrct2/windows/game_bottom_toolbar.c +++ b/src/openrct2/windows/game_bottom_toolbar.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../input.h" #include "../interface/themes.h" diff --git a/src/openrct2/windows/guest.c b/src/openrct2/windows/guest.c index 163350a2cc..40bce403d7 100644 --- a/src/openrct2/windows/guest.c +++ b/src/openrct2/windows/guest.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../input.h" #include "../management/marketing.h" diff --git a/src/openrct2/windows/guest_list.c b/src/openrct2/windows/guest_list.c index 5abe455c73..84ac5fa8a0 100644 --- a/src/openrct2/windows/guest_list.c +++ b/src/openrct2/windows/guest_list.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/themes.h" #include "../interface/widget.h" diff --git a/src/openrct2/windows/install_track.c b/src/openrct2/windows/install_track.c index 2cb179e3d7..ae8a3feee5 100644 --- a/src/openrct2/windows/install_track.c +++ b/src/openrct2/windows/install_track.c @@ -20,11 +20,12 @@ #include "../interface/widget.h" #include "../interface/window.h" #include "../localisation/localisation.h" +#include "../object/ObjectManager.h" +#include "../platform/platform.h" #include "../ride/ride.h" #include "../ride/track.h" #include "../ride/track_design.h" #include "../ride/TrackDesignRepository.h" -#include "../object/ObjectManager.h" #include "../sprites.h" #include "../util/util.h" #include "error.h" diff --git a/src/openrct2/windows/loadsave.c b/src/openrct2/windows/loadsave.c index ec4755079e..6dd59d621a 100644 --- a/src/openrct2/windows/loadsave.c +++ b/src/openrct2/windows/loadsave.c @@ -15,7 +15,7 @@ #pragma endregion #include -#include "../config.h" +#include "../config/Config.h" #include "../editor.h" #include "../game.h" #include "../interface/themes.h" diff --git a/src/openrct2/windows/map_tooltip.c b/src/openrct2/windows/map_tooltip.c index 25c82a4c79..8b9c37ad78 100644 --- a/src/openrct2/windows/map_tooltip.c +++ b/src/openrct2/windows/map_tooltip.c @@ -14,10 +14,11 @@ *****************************************************************************/ #pragma endregion -#include "../localisation/localisation.h" #include "../input.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../platform/platform.h" static rct_widget window_map_tooltip_widgets[] = { { WWT_IMGBTN, 0, 0, 199, 0, 29, 0xFFFFFFFF, STR_NONE }, diff --git a/src/openrct2/windows/multiplayer.c b/src/openrct2/windows/multiplayer.c index d351409c6e..514da162cc 100644 --- a/src/openrct2/windows/multiplayer.c +++ b/src/openrct2/windows/multiplayer.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../interface/themes.h" #include "../interface/widget.h" #include "../interface/window.h" diff --git a/src/openrct2/windows/new_campaign.c b/src/openrct2/windows/new_campaign.c index 247c6ccf00..204f3b6f7e 100644 --- a/src/openrct2/windows/new_campaign.c +++ b/src/openrct2/windows/new_campaign.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../localisation/localisation.h" #include "../interface/widget.h" diff --git a/src/openrct2/windows/new_ride.c b/src/openrct2/windows/new_ride.c index b6647735fb..796f965277 100644 --- a/src/openrct2/windows/new_ride.c +++ b/src/openrct2/windows/new_ride.c @@ -15,7 +15,7 @@ #pragma endregion #include "../audio/audio.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/widget.h" #include "../interface/window.h" diff --git a/src/openrct2/windows/news_options.c b/src/openrct2/windows/news_options.c index b81d0567fb..026eedef12 100644 --- a/src/openrct2/windows/news_options.c +++ b/src/openrct2/windows/news_options.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../interface/widget.h" #include "../interface/window.h" #include "../localisation/localisation.h" @@ -33,23 +33,23 @@ typedef struct notification_def { } notification_def; static const notification_def NewsItemOptionDefinitions[] = { - { NOTIFICATION_CATEGORY_PARK, STR_NOTIFICATION_PARK_AWARD, offsetof(notification_configuration, park_award) }, - { NOTIFICATION_CATEGORY_PARK, STR_NOTIFICATION_PARK_MARKETING_CAMPAIGN_FINISHED, offsetof(notification_configuration, park_marketing_campaign_finished) }, - { NOTIFICATION_CATEGORY_PARK, STR_NOTIFICATION_PARK_WARNINGS, offsetof(notification_configuration, park_warnings) }, - { NOTIFICATION_CATEGORY_PARK, STR_NOTIFICATION_PARK_RATING_WARNINGS, offsetof(notification_configuration, park_rating_warnings) }, - { NOTIFICATION_CATEGORY_RIDE, STR_NOTIFICATION_RIDE_BROKEN_DOWN, offsetof(notification_configuration, ride_broken_down) }, - { NOTIFICATION_CATEGORY_RIDE, STR_NOTIFICATION_RIDE_CRASHED, offsetof(notification_configuration, ride_crashed) }, - { NOTIFICATION_CATEGORY_RIDE, STR_NOTIFICATION_RIDE_WARNINGS, offsetof(notification_configuration, ride_warnings) }, - { NOTIFICATION_CATEGORY_RIDE, STR_NOTIFICATION_RIDE_RESEARCHED, offsetof(notification_configuration, ride_researched) }, - { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_WARNINGS, offsetof(notification_configuration, guest_warnings) }, - { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_LOST, offsetof(notification_configuration, guest_lost) }, - { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_LEFT_PARK, offsetof(notification_configuration, guest_left_park) }, - { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_QUEUING_FOR_RIDE, offsetof(notification_configuration, guest_queuing_for_ride) }, - { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_ON_RIDE, offsetof(notification_configuration, guest_on_ride) }, - { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_LEFT_RIDE, offsetof(notification_configuration, guest_left_ride) }, - { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_BOUGHT_ITEM, offsetof(notification_configuration, guest_bought_item) }, - { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_USED_FACILITY, offsetof(notification_configuration, guest_used_facility) }, - { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_DIED, offsetof(notification_configuration, guest_died) }, + { NOTIFICATION_CATEGORY_PARK, STR_NOTIFICATION_PARK_AWARD, offsetof(NotificationConfiguration, park_award) }, + { NOTIFICATION_CATEGORY_PARK, STR_NOTIFICATION_PARK_MARKETING_CAMPAIGN_FINISHED, offsetof(NotificationConfiguration, park_marketing_campaign_finished) }, + { NOTIFICATION_CATEGORY_PARK, STR_NOTIFICATION_PARK_WARNINGS, offsetof(NotificationConfiguration, park_warnings) }, + { NOTIFICATION_CATEGORY_PARK, STR_NOTIFICATION_PARK_RATING_WARNINGS, offsetof(NotificationConfiguration, park_rating_warnings) }, + { NOTIFICATION_CATEGORY_RIDE, STR_NOTIFICATION_RIDE_BROKEN_DOWN, offsetof(NotificationConfiguration, ride_broken_down) }, + { NOTIFICATION_CATEGORY_RIDE, STR_NOTIFICATION_RIDE_CRASHED, offsetof(NotificationConfiguration, ride_crashed) }, + { NOTIFICATION_CATEGORY_RIDE, STR_NOTIFICATION_RIDE_WARNINGS, offsetof(NotificationConfiguration, ride_warnings) }, + { NOTIFICATION_CATEGORY_RIDE, STR_NOTIFICATION_RIDE_RESEARCHED, offsetof(NotificationConfiguration, ride_researched) }, + { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_WARNINGS, offsetof(NotificationConfiguration, guest_warnings) }, + { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_LOST, offsetof(NotificationConfiguration, guest_lost) }, + { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_LEFT_PARK, offsetof(NotificationConfiguration, guest_left_park) }, + { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_QUEUING_FOR_RIDE, offsetof(NotificationConfiguration, guest_queuing_for_ride) }, + { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_ON_RIDE, offsetof(NotificationConfiguration, guest_on_ride) }, + { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_LEFT_RIDE, offsetof(NotificationConfiguration, guest_left_ride) }, + { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_BOUGHT_ITEM, offsetof(NotificationConfiguration, guest_bought_item) }, + { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_USED_FACILITY, offsetof(NotificationConfiguration, guest_used_facility) }, + { NOTIFICATION_CATEGORY_GUEST, STR_NOTIFICATION_GUEST_DIED, offsetof(NotificationConfiguration, guest_died) }, }; enum WINDOW_NEWS_WIDGET_IDX { diff --git a/src/openrct2/windows/options.c b/src/openrct2/windows/options.c index a4562c82d4..db33f67030 100644 --- a/src/openrct2/windows/options.c +++ b/src/openrct2/windows/options.c @@ -24,8 +24,9 @@ #include "../audio/audio.h" #include "../audio/AudioMixer.h" -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" +#include "../drawing/IDrawingEngine.h" #include "../interface/themes.h" #include "../interface/viewport.h" #include "../interface/widget.h" diff --git a/src/openrct2/windows/park.c b/src/openrct2/windows/park.c index 9184c614c8..b51a0f2b4f 100644 --- a/src/openrct2/windows/park.c +++ b/src/openrct2/windows/park.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../localisation/date.h" #include "../localisation/localisation.h" diff --git a/src/openrct2/windows/player.c b/src/openrct2/windows/player.c index 4fab90b0a4..e4a809cc49 100644 --- a/src/openrct2/windows/player.c +++ b/src/openrct2/windows/player.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../input.h" #include "../management/marketing.h" diff --git a/src/openrct2/windows/ride.c b/src/openrct2/windows/ride.c index ea7c25fe9a..e8176f75e0 100644 --- a/src/openrct2/windows/ride.c +++ b/src/openrct2/windows/ride.c @@ -16,7 +16,7 @@ #include "../audio/audio.h" #include "../cheats.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../input.h" #include "../interface/themes.h" diff --git a/src/openrct2/windows/ride_construction.c b/src/openrct2/windows/ride_construction.c index 2f45222a2d..97ee941e07 100644 --- a/src/openrct2/windows/ride_construction.c +++ b/src/openrct2/windows/ride_construction.c @@ -16,7 +16,7 @@ #include "../audio/audio.h" #include "../cheats.h" -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" #include "../game.h" #include "../input.h" diff --git a/src/openrct2/windows/ride_list.c b/src/openrct2/windows/ride_list.c index 1cd866831e..7522a006b7 100644 --- a/src/openrct2/windows/ride_list.c +++ b/src/openrct2/windows/ride_list.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../ride/ride.h" #include "../localisation/localisation.h" diff --git a/src/openrct2/windows/save_prompt.c b/src/openrct2/windows/save_prompt.c index 14a82a3364..eacc28ae91 100644 --- a/src/openrct2/windows/save_prompt.c +++ b/src/openrct2/windows/save_prompt.c @@ -15,7 +15,7 @@ #pragma endregion #include "../audio/audio.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../localisation/localisation.h" #include "../interface/themes.h" diff --git a/src/openrct2/windows/server_list.c b/src/openrct2/windows/server_list.c index 63e505797b..729aabb888 100644 --- a/src/openrct2/windows/server_list.c +++ b/src/openrct2/windows/server_list.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../interface/colour.h" #include "../interface/themes.h" #include "../interface/widget.h" diff --git a/src/openrct2/windows/server_start.c b/src/openrct2/windows/server_start.c index 5ccb8d112a..2667ccd5b1 100644 --- a/src/openrct2/windows/server_start.c +++ b/src/openrct2/windows/server_start.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../interface/themes.h" #include "../interface/widget.h" #include "../interface/window.h" diff --git a/src/openrct2/windows/shortcut_key_change.c b/src/openrct2/windows/shortcut_key_change.c index 90f0f753ab..5a9f60f654 100644 --- a/src/openrct2/windows/shortcut_key_change.c +++ b/src/openrct2/windows/shortcut_key_change.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../interface/keyboard_shortcut.h" #include "../interface/themes.h" #include "../interface/window.h" diff --git a/src/openrct2/windows/shortcut_keys.c b/src/openrct2/windows/shortcut_keys.c index b361c557d7..29d39cc130 100644 --- a/src/openrct2/windows/shortcut_keys.c +++ b/src/openrct2/windows/shortcut_keys.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../interface/window.h" #include "../interface/widget.h" #include "../localisation/localisation.h" diff --git a/src/openrct2/windows/sign.c b/src/openrct2/windows/sign.c index ca34ee7794..865e518f50 100644 --- a/src/openrct2/windows/sign.c +++ b/src/openrct2/windows/sign.c @@ -15,7 +15,7 @@ #pragma endregion #include "../game.h" -#include "../config.h" +#include "../config/Config.h" #include "../localisation/localisation.h" #include "../interface/viewport.h" #include "../interface/widget.h" diff --git a/src/openrct2/windows/staff.c b/src/openrct2/windows/staff.c index c9ba7217a0..0665f9ca17 100644 --- a/src/openrct2/windows/staff.c +++ b/src/openrct2/windows/staff.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/viewport.h" #include "../interface/widget.h" diff --git a/src/openrct2/windows/staff_list.c b/src/openrct2/windows/staff_list.c index 5f09ad4e97..496fe73a4b 100644 --- a/src/openrct2/windows/staff_list.c +++ b/src/openrct2/windows/staff_list.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" #include "../game.h" #include "../input.h" diff --git a/src/openrct2/windows/text_input.c b/src/openrct2/windows/text_input.c index c3da45c745..b748b6420c 100644 --- a/src/openrct2/windows/text_input.c +++ b/src/openrct2/windows/text_input.c @@ -21,7 +21,7 @@ * that is used for inputing new text for ride names and peep names. */ -#include "../config.h" +#include "../config/Config.h" #include "../platform/platform.h" #include "../interface/window.h" #include "../interface/widget.h" diff --git a/src/openrct2/windows/themes.c b/src/openrct2/windows/themes.c index b5c8db328b..85867e5ec6 100644 --- a/src/openrct2/windows/themes.c +++ b/src/openrct2/windows/themes.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../drawing/drawing.h" #include "../input.h" diff --git a/src/openrct2/windows/title_editor.c b/src/openrct2/windows/title_editor.c index 9dcb7eae06..706bbdd785 100644 --- a/src/openrct2/windows/title_editor.c +++ b/src/openrct2/windows/title_editor.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" #include "../game.h" #include "../input.h" diff --git a/src/openrct2/windows/title_exit.c b/src/openrct2/windows/title_exit.c index ac7823f0c5..f2d40c1346 100644 --- a/src/openrct2/windows/title_exit.c +++ b/src/openrct2/windows/title_exit.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../sprites.h" #include "../localisation/localisation.h" diff --git a/src/openrct2/windows/title_menu.c b/src/openrct2/windows/title_menu.c index cd82e98a43..c0126076dc 100644 --- a/src/openrct2/windows/title_menu.c +++ b/src/openrct2/windows/title_menu.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../editor.h" #include "../game.h" #include "../input.h" diff --git a/src/openrct2/windows/title_options.c b/src/openrct2/windows/title_options.c index 3471b43c97..01a09fcf9c 100644 --- a/src/openrct2/windows/title_options.c +++ b/src/openrct2/windows/title_options.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../intro.h" #include "../localisation/localisation.h" diff --git a/src/openrct2/windows/title_scenarioselect.c b/src/openrct2/windows/title_scenarioselect.c index 38b9d018ab..2383048458 100644 --- a/src/openrct2/windows/title_scenarioselect.c +++ b/src/openrct2/windows/title_scenarioselect.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../audio/audio.h" #include "../localisation/date.h" #include "../localisation/localisation.h" diff --git a/src/openrct2/windows/top_toolbar.c b/src/openrct2/windows/top_toolbar.c index e5c9eaa87e..4608b1a769 100644 --- a/src/openrct2/windows/top_toolbar.c +++ b/src/openrct2/windows/top_toolbar.c @@ -16,7 +16,7 @@ #include "../audio/audio.h" #include "../cheats.h" -#include "../config.h" +#include "../config/Config.h" #include "../editor.h" #include "../game.h" #include "../input.h" diff --git a/src/openrct2/windows/track_list.c b/src/openrct2/windows/track_list.c index 122182ce26..7f86bcf992 100644 --- a/src/openrct2/windows/track_list.c +++ b/src/openrct2/windows/track_list.c @@ -15,7 +15,8 @@ #pragma endregion #include "../audio/audio.h" -#include "../config.h" +#include "../config/Config.h" +#include "../drawing/IDrawingEngine.h" #include "../editor.h" #include "../interface/themes.h" #include "../interface/widget.h" diff --git a/src/openrct2/windows/view_clipping.c b/src/openrct2/windows/view_clipping.c index 97607d4769..d2ca97cf91 100644 --- a/src/openrct2/windows/view_clipping.c +++ b/src/openrct2/windows/view_clipping.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include "../config.h" +#include "../config/Config.h" #include "../interface/themes.h" #include "../interface/widget.h" #include "../interface/window.h" diff --git a/src/openrct2/world/climate.c b/src/openrct2/world/climate.c index 2d4ab772cb..79c5ca8288 100644 --- a/src/openrct2/world/climate.c +++ b/src/openrct2/world/climate.c @@ -17,7 +17,7 @@ #include "../audio/audio.h" #include "../audio/AudioMixer.h" #include "../cheats.h" -#include "../config.h" +#include "../config/Config.h" #include "../drawing/drawing.h" #include "../game.h" #include "../interface/window.h" diff --git a/src/openrct2/world/map.c b/src/openrct2/world/map.c index 24be817085..98e5d831f3 100644 --- a/src/openrct2/world/map.c +++ b/src/openrct2/world/map.c @@ -17,7 +17,7 @@ #include "../rct2/addresses.h" #include "../audio/audio.h" #include "../cheats.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/Cursors.h" #include "../interface/window.h" diff --git a/src/openrct2/world/park.c b/src/openrct2/world/park.c index 5c5d0b5e1e..6101332ff7 100644 --- a/src/openrct2/world/park.c +++ b/src/openrct2/world/park.c @@ -15,7 +15,7 @@ #pragma endregion #include "../cheats.h" -#include "../config.h" +#include "../config/Config.h" #include "../game.h" #include "../interface/colour.h" #include "../interface/window.h" diff --git a/test/testpaint/compat.c b/test/testpaint/compat.c index 7b8a1a671e..9260c53e97 100644 --- a/test/testpaint/compat.c +++ b/test/testpaint/compat.c @@ -14,7 +14,7 @@ *****************************************************************************/ #pragma endregion -#include +#include #include #include #include @@ -72,8 +72,7 @@ int object_entry_group_counts[] = { 1 // scenario text }; - -general_configuration gConfigGeneral; +GeneralConfiguration gConfigGeneral; uint16 gMapSelectFlags; uint16 gMapSelectType; rct_xy16 gMapSelectPositionA; diff --git a/test/tests/CMakeLists.txt b/test/tests/CMakeLists.txt index f92f61bae8..763fa706f7 100644 --- a/test/tests/CMakeLists.txt +++ b/test/tests/CMakeLists.txt @@ -55,6 +55,22 @@ include_directories("../../src") set(GTEST_LIBRARIES gtest gtest_main pthread) +# Some most common files required in tests +set(COMMON_TEST_SOURCES + "../../src/openrct2/core/Console.cpp" + "../../src/openrct2/core/Diagnostics.cpp" + "../../src/openrct2/core/Guard.cpp" + "../../src/openrct2/core/String.cpp" + "../../src/openrct2/diagnostic.c" + "../../src/openrct2/localisation/format_codes.c" + "../../src/openrct2/localisation/utf8.c" + "../../src/openrct2/util/util.c" + "../../src/openrct2/Version.cpp" + ) + +# Create a re-usable library to save some compilation time +add_library(test-common STATIC ${COMMON_TEST_SOURCES}) + # Start of our tests # sawyercoding test @@ -73,16 +89,28 @@ add_test(NAME sawyercoding COMMAND test_sawyercoding) set(LANGUAGEPACK_TEST_SOURCES "LanguagePackTest.cpp" "../../src/openrct2/localisation/LanguagePack.cpp" - "../../src/openrct2/core/Console.cpp" - "../../src/openrct2/core/Diagnostics.cpp" - "../../src/openrct2/core/Guard.cpp" - "../../src/openrct2/core/String.cpp" - "../../src/openrct2/diagnostic.c" - "../../src/openrct2/localisation/format_codes.c" - "../../src/openrct2/localisation/utf8.c" - "../../src/openrct2/util/util.c" - "../../src/openrct2/Version.cpp" ) add_executable(test_languagepack ${LANGUAGEPACK_TEST_SOURCES}) -target_link_libraries(test_languagepack ${GTEST_LIBRARIES} dl z SDL2 SDL2_ttf ssl crypto) +target_link_libraries(test_languagepack ${GTEST_LIBRARIES} test-common dl z SDL2) add_test(NAME languagepack COMMAND test_languagepack) + +# INI test +set(INI_TEST_SOURCES + "IniWriterTest.cpp" + "IniReaderTest.cpp" + "../../src/openrct2/config/IniReader.cpp" + "../../src/openrct2/config/IniWriter.cpp" + "../../src/openrct2/core/IStream.cpp" + "../../src/openrct2/core/MemoryStream.cpp" + ) +add_executable(test_ini ${INI_TEST_SOURCES}) +target_link_libraries(test_ini ${GTEST_LIBRARIES} test-common dl z) +add_test(NAME ini COMMAND test_ini) + +# String test +set(STRING_TEST_SOURCES + "StringTest.cpp" + ) +add_executable(test_string ${STRING_TEST_SOURCES}) +target_link_libraries(test_string ${GTEST_LIBRARIES} test-common dl z) +add_test(NAME string COMMAND test_string) diff --git a/test/tests/IniReaderTest.cpp b/test/tests/IniReaderTest.cpp new file mode 100644 index 0000000000..05c1c73b5a --- /dev/null +++ b/test/tests/IniReaderTest.cpp @@ -0,0 +1,132 @@ +#include +#include +#include +#include "openrct2/config/ConfigEnum.hpp" +#include "openrct2/config/IniReader.hpp" +#include "openrct2/core/MemoryStream.h" +#include "openrct2/core/Util.hpp" + +class IniReaderTest : public testing::Test +{ +protected: + static const std::string predefined; + static const std::string duplicate; + static const std::string untrimmed; +}; + +static auto Enum_Currency = ConfigEnum({}); + +TEST_F(IniReaderTest, create_empty) +{ + MemoryStream ms(0); + ASSERT_EQ(ms.CanRead(), true); + ASSERT_EQ(ms.CanWrite(), true); + IIniReader * ir = CreateIniReader(&ms); + ASSERT_NE(ir, nullptr); + ASSERT_EQ(ir->GetBoolean("nobody", true), true); + ASSERT_EQ(ir->GetCString("expects", nullptr), nullptr); + ASSERT_EQ(ir->GetEnum("spanish", 12345, Enum_Currency), 12345); + ASSERT_EQ(ir->GetFloat("inquisition", 1.234f), 1.234f); + ASSERT_EQ(ir->GetSint32("universal_answer", 42), 42); + delete ir; +} + +TEST_F(IniReaderTest, read_prepared) +{ + MemoryStream ms(predefined.c_str(), predefined.size()); + ASSERT_EQ(ms.CanRead(), true); + ASSERT_EQ(ms.CanWrite(), false); + IIniReader * ir = CreateIniReader(&ms); + ASSERT_NE(ir, nullptr); + ASSERT_EQ(ir->ReadSection("doesnt_exist"), false); + ASSERT_EQ(ir->ReadSection("bool"), true); + // name of section + ASSERT_EQ(ir->GetSint32("bool", 42), 42); + // value from different section + ASSERT_EQ(ir->GetSint32("one", 42), 42); + // existing value as different type + ASSERT_EQ(ir->GetSint32("boolval", 42), 42); + ASSERT_EQ(ir->GetBoolean("boolval", false), true); + // skip one section + ASSERT_EQ(ir->ReadSection("string"), true); + // values from different sections + ASSERT_EQ(ir->GetSint32("one", 42), 42); + ASSERT_EQ(ir->GetBoolean("boolval", false), true); + const utf8 * str = ir->GetCString("path", nullptr); + ASSERT_STREQ(str, u8"C:'\\some/dir\\here/神鷹暢遊"); + Memory::Free(str); + // go back a section + ASSERT_EQ(ir->ReadSection("int"), true); + ASSERT_EQ(ir->GetSint32("one", 42), 1); + delete ir; +} + +TEST_F(IniReaderTest, read_duplicate) +{ + MemoryStream ms(duplicate.c_str(), duplicate.size()); + ASSERT_EQ(ms.CanRead(), true); + ASSERT_EQ(ms.CanWrite(), false); + IIniReader * ir = CreateIniReader(&ms); + ASSERT_NE(ir, nullptr); + // there should only be data from the last section + ASSERT_EQ(ir->ReadSection("section"), true); + ASSERT_EQ(ir->GetBoolean("one", false), false); + ASSERT_EQ(ir->GetBoolean("two", false), false); + ASSERT_EQ(ir->GetBoolean("three", false), true); + ASSERT_EQ(ir->ReadSection("section"), true); + // try switching to another section + ASSERT_EQ(ir->ReadSection("doesnt_exist"), false); + // make sure we are still in the same section + ASSERT_EQ(ir->GetBoolean("one", false), false); + ASSERT_EQ(ir->GetBoolean("two", false), false); + ASSERT_EQ(ir->GetBoolean("three", false), true); + ASSERT_EQ(ir->GetSint32("fortytwo", 100), 41); + ASSERT_EQ(ir->ReadSection("section"), true); + // test 4 times, there are only 3 sections + ASSERT_EQ(ir->ReadSection("section"), true); + delete ir; +} + +TEST_F(IniReaderTest, read_untrimmed) +{ + MemoryStream ms(untrimmed.c_str(), untrimmed.size()); + ASSERT_EQ(ms.CanRead(), true); + ASSERT_EQ(ms.CanWrite(), false); + IIniReader * ir = CreateIniReader(&ms); + ASSERT_NE(ir, nullptr); + // there should only be data from the last section + ASSERT_EQ(ir->ReadSection("section"), true); + ASSERT_EQ(ir->GetBoolean("one", false), true); + const utf8 * str = ir->GetCString("str", nullptr); + ASSERT_STREQ(str, " xxx "); + Memory::Free(str); + ASSERT_EQ(ir->GetString("str", "yyy"), " xxx "); + ASSERT_EQ(ir->GetString("nosuchthing", " yyy "), " yyy "); + delete ir; +} + +const std::string IniReaderTest::predefined = + "[bool]\n" + "boolval = true\n\n" + "[int]\n" + "one = 1\n" + "zero = 0\n\n" + "[string]\n" + "path = " + "\"C:'\\\\some/dir\\\\here/\xE7\xA5\x9E\xE9\xB7\xB9\xE6\x9A\xA2\xE9\x81\x8A\"\n"; + +const std::string IniReaderTest::duplicate = + "[section]\n" + "one = true\n" + "fortytwo = 13\n" + "[section]\n" + "two = true\n" + "[section]\n" + "three = true\n" + "fortytwo = 42\n" + "fortytwo = 41\n"; + +const std::string IniReaderTest::untrimmed = + "[section]\n" + "one = true \n" + " str = \" xxx \""; diff --git a/test/tests/IniWriterTest.cpp b/test/tests/IniWriterTest.cpp new file mode 100644 index 0000000000..dcfdbe587a --- /dev/null +++ b/test/tests/IniWriterTest.cpp @@ -0,0 +1,209 @@ +#include +#include +#include "openrct2/config/ConfigEnum.hpp" +#include "openrct2/config/IniWriter.hpp" +#include "openrct2/core/MemoryStream.h" +#include "openrct2/platform/platform.h" + +class IniWriterTest : public testing::Test +{ +}; + +static auto Enum_Currency = ConfigEnum({ + ConfigEnumEntry("GBP", 1), +}); + +TEST_F(IniWriterTest, create_empty) +{ + MemoryStream ms(0); + ASSERT_EQ(ms.CanRead(), true); + ASSERT_EQ(ms.CanWrite(), true); + IIniWriter * iw = CreateIniWriter(&ms); + ASSERT_NE(iw, nullptr); + delete iw; +} + +TEST_F(IniWriterTest, create_one_section) +{ + MemoryStream ms(1000); + IIniWriter * iw = CreateIniWriter(&ms); + ASSERT_NE(iw, nullptr); + iw->WriteSection("OpenRCT2"); + uint8 null_terminator = 0; + ms.Write(&null_terminator, 1); + ASSERT_GE(ms.GetPosition(), 12); + ASSERT_LE(ms.GetPosition(), 13); // Accomodate for varying-sized newline (Windows) + ASSERT_EQ(ms.GetLength(), ms.GetPosition()); + ms.SetPosition(0); + const char * ini = (const char *)ms.ReadString(); + ASSERT_STREQ(ini, "[OpenRCT2]" PLATFORM_NEWLINE); + Memory::Free(ini); + delete iw; +} + +TEST_F(IniWriterTest, create_multiple_sections) +{ + MemoryStream ms(1000); + IIniWriter * iw = CreateIniWriter(&ms); + ASSERT_NE(iw, nullptr); + iw->WriteSection("OpenRCT1"); + iw->WriteSection("OpenRCT2"); + iw->WriteSection("OpenRCT3"); + iw->WriteSection("OpenRCT4"); + uint8 null_terminator = 0; + ms.Write(&null_terminator, 1); + ASSERT_GE(ms.GetPosition(), 48); + ASSERT_LE(ms.GetPosition(), 55); // Accomodate for varying-sized newline (Windows) + ASSERT_EQ(ms.GetLength(), ms.GetPosition()); + ms.SetPosition(0); + const char * ini = (const char *)ms.ReadString(); + ASSERT_STREQ(ini, "[OpenRCT1]" PLATFORM_NEWLINE PLATFORM_NEWLINE "[OpenRCT2]" PLATFORM_NEWLINE PLATFORM_NEWLINE + "[OpenRCT3]" PLATFORM_NEWLINE PLATFORM_NEWLINE "[OpenRCT4]" PLATFORM_NEWLINE); + Memory::Free(ini); + delete iw; +} + +TEST_F(IniWriterTest, create_loose_bool_entry) +{ + MemoryStream ms(1000); + IIniWriter * iw = CreateIniWriter(&ms); + ASSERT_NE(iw, nullptr); + iw->WriteBoolean("boolval", true); + uint8 null_terminator = 0; + ms.Write(&null_terminator, 1); + ASSERT_GE(ms.GetPosition(), 16); + ASSERT_LE(ms.GetPosition(), 17); // Accomodate for varying-sized newline (Windows) + ASSERT_EQ(ms.GetLength(), ms.GetPosition()); + ms.SetPosition(0); + const char * ini = (const char *)ms.ReadString(); + ASSERT_STREQ(ini, "boolval = true" PLATFORM_NEWLINE); + Memory::Free(ini); + delete iw; +} + +TEST_F(IniWriterTest, create_loose_enum_entry) +{ + MemoryStream ms(1000); + IIniWriter * iw = CreateIniWriter(&ms); + ASSERT_NE(iw, nullptr); + iw->WriteEnum("by_string", "stringval"); + iw->WriteEnum("sint32", 0, Enum_Currency); + uint8 null_terminator = 0; + ms.Write(&null_terminator, 1); + ASSERT_GE(ms.GetPosition(), 34); + ASSERT_LE(ms.GetPosition(), 36); // Accomodate for varying-sized newline (Windows) + ASSERT_EQ(ms.GetLength(), ms.GetPosition()); + ms.SetPosition(0); + const char * ini = (const char *)ms.ReadString(); + ASSERT_STREQ(ini, "by_string = stringval" PLATFORM_NEWLINE "sint32 = 0" PLATFORM_NEWLINE); + Memory::Free(ini); + delete iw; +} + +TEST_F(IniWriterTest, create_loose_float_entry) +{ + MemoryStream ms(1000); + IIniWriter * iw = CreateIniWriter(&ms); + ASSERT_NE(iw, nullptr); + iw->WriteFloat("one", 1.); + uint8 null_terminator = 0; + ms.Write(&null_terminator, 1); + ASSERT_GE(ms.GetPosition(), 16); + ASSERT_LE(ms.GetPosition(), 17); // Accomodate for varying-sized newline (Windows) + ASSERT_EQ(ms.GetLength(), ms.GetPosition()); + ms.SetPosition(0); + const char * ini = (const char *)ms.ReadString(); + // This will be non-fatal due to float. + EXPECT_STREQ(ini, "one = 1.000000" PLATFORM_NEWLINE); + Memory::Free(ini); + delete iw; +} + +TEST_F(IniWriterTest, create_loose_sint32_entry) +{ + MemoryStream ms(1000); + IIniWriter * iw = CreateIniWriter(&ms); + ASSERT_NE(iw, nullptr); + iw->WriteSint32("one", 1); + iw->WriteSint32("zero", 0); + iw->WriteSint32("minusone", -1); + iw->WriteSint32("intmin", (std::numeric_limits::min)()); + iw->WriteSint32("intmax", (std::numeric_limits::max)()); + uint8 null_terminator = 0; + ms.Write(&null_terminator, 1); + ASSERT_GE(ms.GetPosition(), 73); + ASSERT_LE(ms.GetPosition(), 78); // Accomodate for varying-sized newline (Windows) + ASSERT_EQ(ms.GetLength(), ms.GetPosition()); + ms.SetPosition(0); + const char * ini = (const char *)ms.ReadString(); + ASSERT_STREQ(ini, "one = 1" PLATFORM_NEWLINE "zero = 0" PLATFORM_NEWLINE "minusone = -1" PLATFORM_NEWLINE + "intmin = -2147483648" PLATFORM_NEWLINE "intmax = 2147483647" PLATFORM_NEWLINE); + Memory::Free(ini); + delete iw; +} + +TEST_F(IniWriterTest, create_loose_string_entry) +{ + MemoryStream ms(1000); + IIniWriter * iw = CreateIniWriter(&ms); + ASSERT_NE(iw, nullptr); + iw->WriteString("path", u8"C:'\\some/dir\\here/神鷹暢遊"); + uint8 null_terminator = 0; + ms.Write(&null_terminator, 1); + ASSERT_GE(ms.GetPosition(), 43); + ASSERT_LE(ms.GetPosition(), 44); // Accomodate for varying-sized newline (Windows) + ASSERT_EQ(ms.GetLength(), ms.GetPosition()); + ms.SetPosition(0); + const char * ini = (const char *)ms.ReadString(); + ASSERT_STREQ(ini, "path = \"C:'\\\\some/dir\\\\here/\xE7\xA5\x9E\xE9\xB7\xB9\xE6\x9A\xA2\xE9\x81\x8A\"" PLATFORM_NEWLINE); + Memory::Free(ini); + delete iw; +} + +TEST_F(IniWriterTest, create_multiple_section_with_values) +{ + MemoryStream ms(1000); + IIniWriter * iw = CreateIniWriter(&ms); + ASSERT_NE(iw, nullptr); + iw->WriteSection("bool"); + iw->WriteBoolean("boolval", true); + iw->WriteSection("int"); + iw->WriteSint32("one", 1); + iw->WriteSint32("zero", 0); + iw->WriteSection("string"); + iw->WriteString("path", u8"C:'\\some/dir\\here/神鷹暢遊"); + uint8 null_terminator = 0; + ms.Write(&null_terminator, 1); + ASSERT_GE(ms.GetPosition(), 99); + ASSERT_LE(ms.GetPosition(), 108); // Accomodate for varying-sized newline (Windows) + ASSERT_EQ(ms.GetLength(), ms.GetPosition()); + ms.SetPosition(0); + const char * ini = (const char *)ms.ReadString(); + ASSERT_STREQ(ini, + "[bool]" PLATFORM_NEWLINE "boolval = true" PLATFORM_NEWLINE PLATFORM_NEWLINE "[int]" PLATFORM_NEWLINE + "one = 1" PLATFORM_NEWLINE "zero = 0" PLATFORM_NEWLINE PLATFORM_NEWLINE "[string]" PLATFORM_NEWLINE "path = " + "\"C:'\\\\some/dir\\\\here/\xE7\xA5\x9E\xE9\xB7\xB9\xE6\x9A\xA2\xE9\x81\x8A\"" PLATFORM_NEWLINE); + Memory::Free(ini); + delete iw; +} + +TEST_F(IniWriterTest, create_duplicate_sections) +{ + MemoryStream ms(1000); + IIniWriter * iw = CreateIniWriter(&ms); + ASSERT_NE(iw, nullptr); + iw->WriteSection("section"); + iw->WriteSection("section"); + iw->WriteSection("section"); + uint8 null_terminator = 0; + ms.Write(&null_terminator, 1); + ASSERT_GE(ms.GetPosition(), 33); + ASSERT_LE(ms.GetPosition(), 43); // Accomodate for varying-sized newline (Windows) + ASSERT_EQ(ms.GetLength(), ms.GetPosition()); + ms.SetPosition(0); + const char * ini = (const char *)ms.ReadString(); + ASSERT_STREQ(ini, "[section]" PLATFORM_NEWLINE PLATFORM_NEWLINE "[section]" PLATFORM_NEWLINE PLATFORM_NEWLINE + "[section]" PLATFORM_NEWLINE); + Memory::Free(ini); + delete iw; +} diff --git a/test/tests/StringTest.cpp b/test/tests/StringTest.cpp new file mode 100644 index 0000000000..8644c3c19b --- /dev/null +++ b/test/tests/StringTest.cpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +using TCase = std::tuple; + +class StringTest : public testing::TestWithParam +{ +}; + +INSTANTIATE_TEST_CASE_P(TrimData, StringTest, testing::Values( + TCase("string", "string"), + TCase(" string", "string"), + TCase("string ", "string"), + TCase(" some string ", "some string"), + TCase(" ", ""), + TCase("", ""), + TCase("\n", ""), + TCase("\n\n\n\r\n", ""), + TCase("\n\n\n\r\nstring\n\n", "string") +)); +TEST_P(StringTest, Trim) +{ + auto testCase = GetParam(); + std::string input = std::get<0>(testCase); + std::string expected = std::get<1>(testCase); + std::string actual = String::Trim(input); + ASSERT_EQ(expected, actual); +} diff --git a/test/tests/tests.vcxproj b/test/tests/tests.vcxproj index 5b866801fb..02dc0344b5 100644 --- a/test/tests/tests.vcxproj +++ b/test/tests/tests.vcxproj @@ -45,16 +45,17 @@ Console - + + + - \ No newline at end of file