diff --git a/CMakeLists.txt b/CMakeLists.txt index 14b4af5259..c392ed1def 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,8 +36,8 @@ if (DISABLE_NETWORK) add_definitions(-DDISABLE_NETWORK) endif (DISABLE_NETWORK) -set(ORCTLIBS_INCLUDE /usr/local/cross-tools/orctlibs/include) -set(JANSSON_INCLUDE /usr/local/cross-tools/orctlibs/include/jansson) +set(ORCTLIBS_INCLUDE /usr/local/cross-tools/orctlibs/include) +set(JANSSON_INCLUDE /usr/local/cross-tools/orctlibs/include/jansson) set(ORCTLIBS_LIB_DIR /usr/local/cross-tools/orctlibs/lib) set(ORCTLIBS_LIB jansson curl ssl crypto) @@ -50,8 +50,8 @@ file(GLOB_RECURSE ORCT2_SOURCES "src/*.c" "src/*.cpp" "lib/*.c") if (UNIX) # force 32bit build for now and set necessary flags to compile code as is - set(CMAKE_C_FLAGS "-m32 -masm=intel -std=gnu99") - set(CMAKE_CXX_FLAGS "-m32 -std=gnu++11 -masm=intel") + set(CMAKE_C_FLAGS "-m32 -masm=intel -fvar-tracking-assignments -std=gnu99") + set(CMAKE_CXX_FLAGS "-m32 -std=gnu++11 -fvar-tracking-assignments -masm=intel") set(LIB32 /usr/lib32) set(CMAKE_SHARED_LINKER_FLAGS "-m32 -Wl,-melf_i386 -L${LIB32} -lSDL2_ttf") set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}) @@ -63,10 +63,14 @@ if (UNIX) endif (UNIX) INCLUDE_DIRECTORIES(${ORCTLIBS_INCLUDE} ${JANSSON_INCLUDE}) -LINK_DIRECTORIES(${SDL2_LIBRARY_DIRS} ${ORCTLIBS_LIB_DIR}) +LINK_DIRECTORIES(${LINK_DIRECTORIES} ${LIB32} ${SDL2_LIBRARY_DIRS} ${ORCTLIBS_LIB_DIR}) -# build as library for now, replace with add_executable -add_library(${PROJECT} SHARED ${ORCT2_SOURCES}) +if (WIN32) + # build as library for now, replace with add_executable + add_library(${PROJECT} SHARED ${ORCT2_SOURCES}) +else (WIN32) + add_executable(${PROJECT} ${ORCT2_SOURCES}) +endif (WIN32) # install into ${CMAKE_INSTALL_PREFIX}/bin/ #install (TARGETS ${PROJECT} DESTINATION bin) @@ -79,4 +83,3 @@ TARGET_LINK_LIBRARIES(${PROJECT} ${SDL2_LIBRARIES} ${ORCTLIBS_LIB}) if (WIN32) target_link_libraries(${PROJECT} winmm.lib -limm32 -lversion -ldsound ws2_32) endif (WIN32) - diff --git a/install.sh b/install.sh index 06fdc181b3..1400804253 100755 --- a/install.sh +++ b/install.sh @@ -87,7 +87,7 @@ elif [[ `uname` == "Linux" ]]; then apt-cache search libsdl2 apt-cache policy libsdl2-dev:i386 apt-cache policy libsdl2-dev - sudo apt-get install -y --force-yes binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 cmake libsdl2-dev:i386 libsdl2-ttf-dev:i386 gcc-4.8 pkg-config:i386 g++-4.8-multilib gcc-4.8-multilib libjansson-dev:i386 libspeex-dev:i386 libspeexdsp-dev:i386 + sudo apt-get install -y --force-yes binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 cmake libsdl2-dev:i386 libsdl2-ttf-dev:i386 gcc-4.8 pkg-config:i386 g++-4.8-multilib gcc-4.8-multilib libjansson-dev:i386 libspeex-dev:i386 libspeexdsp-dev:i386 libcurl4-openssl-dev:i386 libcrypto++-dev:i386 export CC=gcc-4.8 export CXX=g++-4.8 fi diff --git a/src/audio/audio.c b/src/audio/audio.c index 07c940768b..a919d9b241 100644 --- a/src/audio/audio.c +++ b/src/audio/audio.c @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ @@ -556,7 +556,8 @@ int sound_channel_load_file2(int channel, const char* filename, int offset) if (sound_channel_is_playing(channel)) { sound_channel_stop(channel); } - if (SUCCEEDED(sound_channel_load_file(channel, filename, offset))) { + int load_result = sound_channel_load_file(channel, filename, offset); + if (load_result >= 0) { RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[channel].var_4 = 0; return 1; } @@ -961,7 +962,7 @@ int sound_play(rct_sound* sound, int looping, int volume, int pan, int frequency } else { playflags = 0; } - if (SUCCEEDED(sound->dsbuffer->lpVtbl->Play(sound->dsbuffer, 0, 0, playflags))) + if (SUCCEEDED(sound->dsbuffer->lpVtbl->Play(sound->dsbuffer, 0, 0, playflags))) return 1; } @@ -1497,7 +1498,7 @@ int dsound_create_primary_buffer(int a, int device, int channels, int samples, i if (FAILED(DirectSoundCreate(&dsdevice->guid, &RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), 0))) { return 0; } - if (FAILED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->SetCooperativeLevel(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), windows_get_window_handle(), DSSCL_NORMAL)) || + if (FAILED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->SetCooperativeLevel(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), windows_get_window_handle(), DSSCL_NORMAL)) || FAILED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->CreateSoundBuffer(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), &bufferdesc, &RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER), 0))) { RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->Release(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)); RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND) = 0; diff --git a/src/diagnostic.c b/src/diagnostic.c index d2d06d5f7d..4d756348a8 100644 --- a/src/diagnostic.c +++ b/src/diagnostic.c @@ -79,4 +79,4 @@ void diagnostic_log_with_location(int diagnosticLevel, const char *file, const c // Line terminator fprintf(stream, "\n"); -} \ No newline at end of file +} diff --git a/src/diagnostic.h b/src/diagnostic.h index 21029db312..556ff98324 100644 --- a/src/diagnostic.h +++ b/src/diagnostic.h @@ -57,4 +57,4 @@ void diagnostic_log_with_location(int diagnosticLevel, const char *file, const c #endif -#endif \ No newline at end of file +#endif diff --git a/src/drawing/string.c b/src/drawing/string.c index fcca4343e2..3a11a1cdef 100644 --- a/src/drawing/string.c +++ b/src/drawing/string.c @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ @@ -22,6 +22,7 @@ #include "../localisation/localisation.h" #include "../sprites.h" #include "../world/map.h" +#include "../platform/platform.h" #include "drawing.h" static int ttf_get_string_width(const utf8 *text); @@ -353,7 +354,7 @@ void gfx_draw_string_centred(rct_drawpixelinfo *dpi, int format, int x, int y, i } /** - * + * * rct2: 0x006C1E53 * dpi (edi) * args (esi) @@ -407,7 +408,7 @@ int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, i } /** - * + * * rct2: 0x006C2105 * dpi (edi) * args (esi) @@ -441,7 +442,7 @@ int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int gfx_draw_string(dpi, buffer, 0xFE, x, lineY); buffer = get_string_end(buffer) + 1; lineY += lineHeight; - } + } return lineY - y; } @@ -492,7 +493,7 @@ void colour_char(uint8 colour, uint16* current_font_flags, uint8* palette_pointe if (!(*current_font_flags & 2)) { eax = eax & 0x0FF0000FF; } - // Adjust text palette. Store current colour? + // Adjust text palette. Store current colour? palette_pointer[1] = eax & 0xFF; palette_pointer[2] = (eax >> 8) & 0xFF; palette_pointer[3] = (eax >> 16) & 0xFF; @@ -512,7 +513,7 @@ void colour_char_window(uint8 colour, uint16* current_font_flags,uint8* palette_ if (*current_font_flags & 2) { eax |= 0x0A0A00; } - //Adjust text palette. Store current colour? + //Adjust text palette. Store current colour? palette_pointer[1] = eax & 0xFF; palette_pointer[2] = (eax >> 8) & 0xFF; palette_pointer[3] = (eax >> 16) & 0xFF; @@ -521,7 +522,7 @@ void colour_char_window(uint8 colour, uint16* current_font_flags,uint8* palette_ } /** - * + * * rct2: 0x00682702 * dpi (edi) * buffer (esi) @@ -712,7 +713,7 @@ void gfx_draw_string_centred_wrapped_partial(rct_drawpixelinfo *dpi, int x, int lineY = y - ((numLines * lineHeight) / 2); for (int line = 0; line <= numLines; line++) { int halfWidth = gfx_get_string_width(buffer) / 2; - + utf8 *ch = buffer; utf8 *nextCh; int codepoint; @@ -735,7 +736,7 @@ void gfx_draw_string_centred_wrapped_partial(rct_drawpixelinfo *dpi, int x, int buffer = get_string_end(buffer) + 1; lineY += lineHeight; - } + } } static uint32 _ttf_surface_cache_hash(TTF_Font *font, const utf8 *text) @@ -884,7 +885,7 @@ bool ttf_initialise() for (int i = 0; i < 4; i++) { TTFFontDescriptor *fontDesc = &(gCurrentTTFFontSet->size[i]); - + utf8 fontPath[MAX_PATH] = "C:\\Windows\\Fonts\\"; strcat(fontPath, fontDesc->filename); @@ -1000,7 +1001,7 @@ static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, te return; } } - + int fontSize = font_get_size_from_sprite_base(info->font_sprite_base); int drawX = info->x + fontDesc->offset_x; int drawY = info->y + fontDesc->offset_y; diff --git a/src/localisation/localisation.c b/src/localisation/localisation.c index bf532f5639..e39c58a3d9 100644 --- a/src/localisation/localisation.c +++ b/src/localisation/localisation.c @@ -856,7 +856,12 @@ int win1252_to_utf8(utf8string dst, const char *src, int maxBufferLength) int result = WideCharToMultiByte(CP_UTF8, 0, intermediateBuffer, -1, dst, maxBufferLength, NULL, NULL); #else STUB(); - int result = 0; + // we cannot walk past maxBufferLength, but in case we have still space left + // we need one byte for null terminator + int result = strnlen(src, maxBufferLength) + 1; + result = min(result, maxBufferLength); + strncpy(dst, src, maxBufferLength); + dst[maxBufferLength - 1] = '\0'; #endif // _WIN32 if (heapBuffer != NULL) { diff --git a/src/object.c b/src/object.c index 4295cbb146..3bf78c483d 100644 --- a/src/object.c +++ b/src/object.c @@ -56,7 +56,7 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi { uint8 objectType; rct_object_entry openedEntry; - char path[260]; + char path[MAX_PATH]; SDL_RWops* rw; subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), (char*)installedObject + 16); @@ -259,7 +259,7 @@ int object_load_packed(SDL_RWops* rw) } if (entryGroupIndex == object_entry_group_counts[type]){ - // This should never occur. Objects are not loaded before installing a + // This should never occur. Objects are not loaded before installing a // packed object. So there is only one object loaded at this point. log_error("Too many objects of the same type loaded."); rct2_free(chunk); @@ -285,7 +285,7 @@ int object_load_packed(SDL_RWops* rw) } // Convert the entry name to a upper case path name - char path[260]; + char path[MAX_PATH]; char objectPath[9] = { 0 }; for (int i = 0; i < 8; ++i){ if (entry.name[i] != ' ') @@ -400,7 +400,7 @@ int object_calculate_checksum(const rct_object_entry *entry, const char *data, i int object_chunk_load_image_directory(uint8_t** chunk) { int image_start_no = RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32_t); - + // First dword of chunk is no_images int no_images = *((uint32_t*)(*chunk)); *chunk += 4; @@ -754,7 +754,7 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp return flags; } else - { + { rct_window* w = (rct_window*)esi; int width = w->x + w->width - x - 4; @@ -1415,7 +1415,7 @@ int paint_water_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* d return 0; } else if ((flags & 0xFF) == 3){ - if (!((flags >> 8) & 0xFF)) + if (!((flags >> 8) & 0xFF)) gfx_draw_string_centred(dpi, 3326, ecx, edx, 0, (void*)esi); } return flags; @@ -1467,7 +1467,7 @@ int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, switch (type) { case OBJECT_TYPE_RIDE: - return paint_ride_entry(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + return paint_ride_entry(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); case OBJECT_TYPE_SMALL_SCENERY: return paint_small_scenery(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); case OBJECT_TYPE_LARGE_SCENERY: @@ -1477,7 +1477,7 @@ int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, case OBJECT_TYPE_BANNERS: return paint_banner(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); case OBJECT_TYPE_PATHS: - return paint_path_entry(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + return paint_path_entry(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); case OBJECT_TYPE_PATH_BITS: return paint_path_bit(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); case OBJECT_TYPE_SCENERY_SETS: @@ -1503,14 +1503,14 @@ int object_get_scenario_text(rct_object_entry *entry) rct_object_entry *installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); installedObject = object_list_find(entry); - + if (installedObject == NULL){ log_error("Object not found: %.8s", entry->name); RCT2_GLOBAL(0x00F42BD9, uint8) = 0; return 0; } - char path[260]; + char path[MAX_PATH]; char *objectPath = (char*)installedObject + 16; subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), objectPath); @@ -1571,7 +1571,7 @@ int object_get_scenario_text(rct_object_entry *entry) memcpy(gTempObjectLoadName, openedEntry.name, 8); // Not used?? RCT2_GLOBAL(0x009ADAFD, uint8) = 1; - object_paint(openedEntry.flags & 0x0F, 0, 0, 0, 0, (int)chunk, 0, 0); + object_paint(openedEntry.flags & 0x0F, 0, 0, 0, 0, (int)chunk, 0, 0); // Tell text to be loaded into normal address RCT2_GLOBAL(0x009ADAFC, uint8) = 0; // Not used?? @@ -1630,7 +1630,7 @@ rct_object_entry *object_get_next(rct_object_entry *entry) // Skip theme objects pos += *pos * 16 + 1; - // Skip + // Skip pos += 4; return (rct_object_entry*)pos; diff --git a/src/object.h b/src/object.h index 18c11087d9..50ebf7cc86 100644 --- a/src/object.h +++ b/src/object.h @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ @@ -75,7 +75,7 @@ extern int object_entry_group_counts[]; extern int object_entry_group_encoding[]; typedef struct { - uint8 **chunks; + uint8 **chunks; rct_object_entry_extended *entries; } rct_object_entry_group; @@ -122,4 +122,4 @@ char *object_get_name(rct_object_entry *entry); rct_object_filters *get_object_filter(int index); -#endif \ No newline at end of file +#endif diff --git a/src/object_list.c b/src/object_list.c index 7fd147949c..cccd9b3592 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ @@ -115,7 +115,7 @@ static void object_list_sort() objectBuffer = &RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); numObjects = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, sint32); copied = calloc(numObjects, sizeof(uint8)); - + // Get buffer size entry = *objectBuffer; for (i = 0; i < numObjects; i++) @@ -166,7 +166,7 @@ static void object_list_sort() } /** - * + * * rct2: 0x006A93CD */ static void object_list_examine() @@ -237,7 +237,7 @@ static int object_list_query_directory(int *outTotalFiles, uint64 *outTotalFileS } /** - * + * * rct2: 0x006A8B40 */ void object_list_load() @@ -291,17 +291,17 @@ void object_list_load() free(_installedObjectFilters); _installedObjectFilters = NULL; } - + enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char)); if (enumFileHandle != INVALID_HANDLE) { uint32 installed_buffer_size = 0x1000; - + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { fileCount++; if ((installed_buffer_size - current_item_offset) <= 2842){ installed_buffer_size += 0x1000; - RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*) = rct2_realloc(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*), installed_buffer_size); + RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*) = rct2_realloc(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*), installed_buffer_size); if (RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, int) == -1){ log_error("Failed to allocate memory for object list"); rct2_exit_reason(835, 3162); @@ -355,6 +355,11 @@ static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int file rct_plugin_header pluginHeader; uint32 filterVersion = 0; +#ifndef _WIN32 + // TODO: remove me! + log_error("this is to be removed after testing/implementation is done"); + return 0; +#endif log_verbose("loading object list cache (plugin.dat)"); get_plugin_path(path); @@ -391,7 +396,7 @@ static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int file free(_installedObjectFilters); _installedObjectFilters = malloc(sizeof(rct_object_filters) * pluginHeader.object_list_no_items); if (SDL_RWread(file, _installedObjectFilters, sizeof(rct_object_filters) * pluginHeader.object_list_no_items, 1) == 1) { - + SDL_RWclose(file); reset_loaded_objects(); object_list_examine(); @@ -431,7 +436,7 @@ static int object_list_cache_save(int fileCount, uint64 totalFileSize, int fileD SDL_RWops *file; rct_plugin_header pluginHeader; uint32 filterVersion = FILTER_VERSION; - + log_verbose("saving object list cache (plugin.dat)"); pluginHeader.total_files = fileCount | 0x01000000; @@ -519,7 +524,7 @@ void set_load_objects_fail_reason(){ } /** - * + * * rct2: 0x006AA0C6 */ int object_read_and_load_entries(SDL_RWops* rw) @@ -557,7 +562,7 @@ int object_read_and_load_entries(SDL_RWops* rw) } } - free(entries); + free(entries); if (load_fail){ object_unload_all(); RCT2_GLOBAL(0x14241BC, uint32) = 0; @@ -571,7 +576,7 @@ int object_read_and_load_entries(SDL_RWops* rw) /** - * + * * rct2: 0x006A9CE8 */ void object_unload_all() @@ -631,7 +636,7 @@ void object_list_create_hash_table() // Set hash table slot _installedObjectHashTable[index] = installedObject; - + // Next installed object installedObject = object_get_next(installedObject); } @@ -645,8 +650,8 @@ int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8 *entry_type = entry->flags & 0xF; rct_object_entry_group entry_group = object_entry_groups[*entry_type]; - for (*entry_index = 0; - *entry_index < object_entry_group_counts[*entry_type]; + for (*entry_index = 0; + *entry_index < object_entry_group_counts[*entry_type]; ++(*entry_index), entry_group.chunks++, entry_group.entries++){ diff --git a/src/openrct2.c b/src/openrct2.c index d2df37bac4..c6d7a80570 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -135,8 +135,19 @@ static void openrct2_set_exe_path() if (bytesRead == -1) { log_fatal("failed to read /proc/self/exe"); } - exePath[MAX_PATH - 1] = '\0'; - strncpy(gExePath, exePath, MAX_PATH); + exePath[bytesRead] = '\0'; + log_verbose("######################################## Setting exe path to %s", exePath); + char *exeDelimiter = strrchr(exePath, platform_get_path_separator()); + if (exeDelimiter == NULL) + { + log_error("should never happen here"); + gExePath[0] = '\0'; + return; + } + int exeDelimiterIndex = (int)(exeDelimiter - exePath); + + strncpy(gExePath, exePath, exeDelimiterIndex + 1); + gExePath[exeDelimiterIndex] = '\0'; #endif // _WIN32 } diff --git a/src/platform/linux.c b/src/platform/linux.c new file mode 100644 index 0000000000..24d68ca60e --- /dev/null +++ b/src/platform/linux.c @@ -0,0 +1,759 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifdef __linux + +#include +#include +#include +#include +#include +#include "../addresses.h" +#include "../cmdline.h" +#include "../openrct2.h" +#include "../localisation/language.h" +#include "../localisation/currency.h" +#include "../config.h" +#include "platform.h" +#include + +// The name of the mutex used to prevent multiple instances of the game from running +#define SINGLE_INSTANCE_MUTEX_NAME "RollerCoaster Tycoon 2_GSKMUTEX" + +/** + * The function that is called directly from the host application (rct2.exe)'s WinMain. This will be removed when OpenRCT2 can + * be built as a stand alone application. + */ +int main(int argc, const char **argv) +{ + //RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE) = hInstance; + //RCT2_GLOBAL(RCT2_ADDRESS_CMDLINE, LPSTR) = lpCmdLine; + + STUB(); + int run_game = cmdline_run(argv, argc); + if (run_game == 1) + { + openrct2_launch(); + } + + exit(gExitCode); + return gExitCode; +} + +char platform_get_path_separator() +{ + return '/'; +} + +bool platform_file_exists(const utf8 *path) +{ + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len] = '\0'; + free(wPath); + int exists = access(buffer, F_OK) != -1; + log_warning("file '%s' exists = %i", buffer, exists); + return exists; +} + +bool platform_directory_exists(const utf8 *path) +{ + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len] = '\0'; + free(wPath); + struct stat dirinfo; + int result = stat(buffer, &dirinfo); + log_verbose("checking dir %s, result = %d, is_dir = %d", buffer, result, S_ISDIR(dirinfo.st_mode)); + if ((result != 0) || !S_ISDIR(dirinfo.st_mode)) + { + return 0; + } + return 1; +} + +bool platform_original_game_data_exists(const utf8 *path) +{ + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len] = '\0'; + free(wPath); + char checkPath[MAX_PATH]; + sprintf(checkPath, "%s%c%s%c%s", buffer, platform_get_path_separator(), "data", platform_get_path_separator(), "g1.dat"); + return platform_file_exists(checkPath); +} + +mode_t getumask() +{ + mode_t mask = umask(0); + umask(mask); + return 0777 & ~mask; // Keep in mind 0777 is octal +} + +bool platform_ensure_directory_exists(const utf8 *path) +{ + mode_t mask = getumask(); + + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len - 1] = '\0'; + free(wPath); + log_verbose("%s", buffer); + const int result = mkdir(buffer, mask); + if (result == 0 || (result == -1 && errno == EEXIST)) + return true; + return false; +} + +bool platform_directory_delete(const utf8 *path) +{ + STUB(); + return 1; +} + +bool platform_lock_single_instance() +{ + STUB(); + return 1; +} + +typedef struct { + char active; + char pattern[MAX_PATH]; + struct dirent **fileListTemp; + char **paths; + int cnt; + int handle; + void* data; +} enumerate_file_info; +static enumerate_file_info _enumerateFileInfoList[8] = { 0 }; + +char *g_file_pattern; + +static int winfilter(const struct dirent *d) +{ + int entry_length = strnlen(d->d_name, MAX_PATH); + char *name_upper = malloc(entry_length + 1); + if (name_upper == NULL) + { + log_error("out of memory"); + return 0; + } + for (int i = 0; i < entry_length; i++) + { + name_upper[i] = (char)toupper(d->d_name[i]); + } + name_upper[entry_length] = '\0'; + bool match = strstr(name_upper, g_file_pattern) != NULL; + //log_warning("trying matching filename %s, result = %d", name_upper, match); + free(name_upper); + return match; +} + +int platform_enumerate_files_begin(const utf8 *pattern) +{ + int i; + enumerate_file_info *enumFileInfo; + wchar_t *wpattern = utf8_to_widechar(pattern); + int length = min(utf8_length(pattern), MAX_PATH); + char *npattern = malloc(length); + int converted; + converted = wcstombs(npattern, wpattern, length); + npattern[length - 1] = '\0'; + if (converted == MAX_PATH) { + log_warning("truncated string %s", npattern); + } + log_warning("begin file search, pattern: %s", npattern); + + char *file_name = strrchr(npattern, platform_get_path_separator()); + char *dir_name; + if (file_name != NULL) + { + dir_name = strndup(npattern, file_name - npattern); + file_name = &file_name[1]; + } else { + file_name = npattern; + dir_name = strdup("."); + } + + char *smatch = strchr(file_name, '*'); + if ((smatch != file_name) && (smatch != NULL)) + { + log_error("Sorry, can only match '*' at start of filename."); + return -1; + } else { + // '*' found + if (smatch != NULL) + { + // some boundary checking needed + // skip the '*' + smatch = &smatch[1]; + char *match2 = strchr(&smatch[1], '*'); + if (match2 != NULL) + { + log_error("Sorry, can only match one '*' wildcard."); + return -1; + } + } else { + // '*' not found + smatch = file_name; + } + } + char *qmatch = strchr(file_name, '?'); + if ((qmatch != &npattern[length - 1]) && (qmatch != NULL)) + { + log_error("Sorry, can only match '?' at end of filename."); + return -1; + } else { + qmatch = &npattern[length]; + } + int pattern_length = qmatch - smatch; + g_file_pattern = strndup(smatch, pattern_length); + for (int j = 0; j < pattern_length; j++) + { + g_file_pattern[j] = (char)toupper(g_file_pattern[j]); + } + log_warning("looking for file matching %s", g_file_pattern); + int cnt; + for (i = 0; i < countof(_enumerateFileInfoList); i++) { + enumFileInfo = &_enumerateFileInfoList[i]; + if (!enumFileInfo->active) { + strncpy(enumFileInfo->pattern, npattern, length); + cnt = scandir(dir_name, &enumFileInfo->fileListTemp, winfilter, alphasort); + if (cnt < 0) + { + break; + } + log_warning("found %d files matching in dir '%s'", cnt, dir_name); + enumFileInfo->cnt = cnt; + enumFileInfo->paths = malloc(cnt * sizeof(char *)); + char **paths = enumFileInfo->paths; + // 256 is size of dirent.d_name + const int buf_len = min(MAX_PATH, 256); + const int dir_name_len = strnlen(dir_name, MAX_PATH); + char separator[] = {platform_get_path_separator(), 0}; + for (int idx = 0; idx < cnt; idx++) + { + struct dirent *d = enumFileInfo->fileListTemp[idx]; + const int entry_len = strnlen(d->d_name, MAX_PATH); + // 1 for separator, 1 for trailing null + paths[idx] = malloc(sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2)); + paths[idx][0] = '\0'; + log_verbose("dir_name: %s", dir_name); + strncat(paths[idx], dir_name, MAX_PATH); + strncat(paths[idx], separator, MAX_PATH); + strncat(paths[idx], d->d_name, MAX_PATH); + log_verbose("paths[%d] = %s", idx, paths[idx]); + } + enumFileInfo->handle = 0; + enumFileInfo->active = 1; + free(dir_name); + free(g_file_pattern); + g_file_pattern = NULL; + free(wpattern); + free(npattern); + return i; + } + } + + free(dir_name); + free(g_file_pattern); + g_file_pattern = NULL; + free(wpattern); + free(npattern); + return -1; +} + +bool platform_enumerate_files_next(int handle, file_info *outFileInfo) +{ + bool result; + enumerate_file_info *enumFileInfo; + + enumFileInfo = &_enumerateFileInfoList[handle]; + + log_verbose("handle = %d", handle); + if (enumFileInfo->handle < enumFileInfo->cnt) { + result = true; + } else { + result = false; + } + + if (result) { + int entryIdx = enumFileInfo->handle++; + struct stat fileInfo; + log_verbose("trying handle %d", entryIdx); + char *fileName = enumFileInfo->paths[entryIdx]; + int statRes; + statRes = stat(fileName, &fileInfo); + if (statRes == -1) { + log_error("failed to stat file '%s'! errno = %i", fileName, errno); + return 0; + } + outFileInfo->path = basename(fileName); + outFileInfo->size = fileInfo.st_size; + outFileInfo->last_modified = fileInfo.st_mtime; + return 1; + } else { + return 0; + } +} + +void platform_enumerate_files_end(int handle) +{ + int i; + enumerate_file_info *enumFileInfo; + + enumFileInfo = &_enumerateFileInfoList[handle]; + int cnt = enumFileInfo->cnt; + for (i = 0; i < cnt; i++) { + free(enumFileInfo->fileListTemp[i]); + free(enumFileInfo->paths[i]); + } + free(enumFileInfo->fileListTemp); + free(enumFileInfo->paths); + // FIXME: this here could have a bug + enumFileInfo->fileListTemp = NULL; + enumFileInfo->handle = 0; + enumFileInfo->active = 0; +} + +static int dirfilter(const struct dirent *d) +{ +#ifdef _DIRENT_HAVE_D_TYPE + if (d->d_type != DT_DIR) + { + return 1; + } else { + return 0; + } +#else +#error implement dirfilter! +#endif // _DIRENT_HAVE_D_TYPE +} + +int platform_enumerate_directories_begin(const utf8 *directory) +{ + int i; + enumerate_file_info *enumFileInfo; + wchar_t *wpattern = utf8_to_widechar(directory); + int length = min(utf8_length(directory), MAX_PATH); + char *npattern = malloc(length); + int converted; + converted = wcstombs(npattern, wpattern, length); + npattern[length - 1] = '\0'; + if (converted == MAX_PATH) { + log_warning("truncated string %s", npattern); + } + log_warning("begin directory listing, path: %s", npattern); + + // TODO: add some checking for stringness and directoryness + + int cnt; + for (i = 0; i < countof(_enumerateFileInfoList); i++) { + enumFileInfo = &_enumerateFileInfoList[i]; + if (!enumFileInfo->active) { + strncpy(enumFileInfo->pattern, npattern, length); + cnt = scandir(npattern, &enumFileInfo->fileListTemp, dirfilter, alphasort); + if (cnt < 0) + { + break; + } + log_warning("found %d files in dir '%s'", cnt, npattern); + enumFileInfo->cnt = cnt; + enumFileInfo->paths = malloc(cnt * sizeof(char *)); + char **paths = enumFileInfo->paths; + // 256 is size of dirent.d_name + const int buf_len = min(MAX_PATH, 256); + const int dir_name_len = strnlen(npattern, MAX_PATH); + char separator[] = {platform_get_path_separator(), 0}; + for (int idx = 0; idx < cnt; idx++) + { + struct dirent *d = enumFileInfo->fileListTemp[idx]; + const int entry_len = strnlen(d->d_name, MAX_PATH); + // 1 for separator, 1 for trailing null + paths[idx] = malloc(sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2)); + paths[idx][0] = '\0'; + log_verbose("dir_name: %s", npattern); + strncat(paths[idx], npattern, MAX_PATH); + strncat(paths[idx], separator, MAX_PATH); + strncat(paths[idx], d->d_name, MAX_PATH); + log_verbose("paths[%d] = %s", idx, paths[idx]); + } + enumFileInfo->handle = 0; + enumFileInfo->active = 1; + free(wpattern); + free(npattern); + return i; + } + } + + free(wpattern); + free(npattern); + return -1; +} + +bool platform_enumerate_directories_next(int handle, utf8 *path) +{ + bool result; + enumerate_file_info *enumFileInfo; + + enumFileInfo = &_enumerateFileInfoList[handle]; + + log_verbose("handle = %d", handle); + if (enumFileInfo->handle < enumFileInfo->cnt) { + result = true; + } else { + result = false; + } + + if (result) { + int entryIdx = enumFileInfo->handle++; + struct stat fileInfo; + log_verbose("trying handle %d", entryIdx); + char *fileName = enumFileInfo->paths[entryIdx]; + int statRes; + statRes = stat(fileName, &fileInfo); + if (statRes == -1) { + log_error("failed to stat file '%s'! errno = %i", fileName, errno); + return 0; + } + // so very, very wrong… + strncpy(path, basename(fileName), MAX_PATH); + strncat(path, "/", MAX_PATH); + path[MAX_PATH - 1] = '\0'; + return 1; + } else { + return 0; + } +} + +void platform_enumerate_directories_end(int handle) +{ + int i; + enumerate_file_info *enumFileInfo; + + enumFileInfo = &_enumerateFileInfoList[handle]; + int cnt = enumFileInfo->cnt; + for (i = 0; i < cnt; i++) { + free(enumFileInfo->fileListTemp[i]); + free(enumFileInfo->paths[i]); + } + free(enumFileInfo->fileListTemp); + free(enumFileInfo->paths); + // FIXME: this here could have a bug + enumFileInfo->fileListTemp = NULL; + enumFileInfo->handle = 0; + enumFileInfo->active = 0; +} + +int platform_get_drives(){ + /* + return GetLogicalDrives(); + */ + STUB(); + return 0xff; +} + +bool platform_file_copy(const utf8 *srcPath, const utf8 *dstPath, bool overwrite) +{ + STUB(); + return 0; +} + +bool platform_file_move(const utf8 *srcPath, const utf8 *dstPath) +{ + STUB(); + return 0; +} + +bool platform_file_delete(const utf8 *path) +{ + STUB(); + return 0; +} + +void platform_hide_cursor() +{ + STUB(); +} + +void platform_show_cursor() +{ + STUB(); +} + +void platform_get_cursor_position(int *x, int *y) +{ + + STUB(); +} + +void platform_set_cursor_position(int x, int y) +{ + STUB(); +} + +unsigned int platform_get_ticks() +{ + STUB(); + return 100; +} + +wchar_t *regular_to_wchar(const char* src) +{ + int len = strnlen(src, MAX_PATH); + wchar_t *w_buffer = malloc((len + 1) * sizeof(wchar_t)); + mbtowc (NULL, NULL, 0); /* reset mbtowc */ + + int max = len; + int i = 0; + while (max > 0) + { + int length; + length = mbtowc(&w_buffer[i], &src[i], max); + if (length < 1) + { + w_buffer[i + 1] = '\0'; + break; + } + i += length; + max -= length; + } + return w_buffer; +} + +void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory) +{ + char buffer[MAX_PATH]; + buffer[0] = '\0'; + log_verbose("buffer = '%s'", buffer); + const char *homedir = getenv("XDG_CONFIG_HOME"); + log_verbose("homedir = '%s'", homedir); + if (homedir == NULL) + { + homedir = getpwuid(getuid())->pw_dir; + log_verbose("homedir was null, used getuid, now is = '%s'", homedir); + if (homedir == NULL) + { + log_error("Couldn't find user home directory"); + return; + } + } + char separator[2] = { platform_get_path_separator(), 0 }; + strncat(buffer, homedir, MAX_PATH); + strncat(buffer, separator, MAX_PATH); + strncat(buffer, "OpenRCT2", MAX_PATH); + strncat(buffer, separator, MAX_PATH); + log_verbose("outPath + OpenRCT2 = '%s'", buffer); + if (subDirectory != NULL && subDirectory[0] != 0) { + log_verbose("adding subDirectory '%s'", subDirectory); + strcat(buffer, subDirectory); + strcat(buffer, separator); + } + int len = strnlen(buffer, MAX_PATH); + wchar_t *w_buffer = regular_to_wchar(buffer); + w_buffer[len] = '\0'; + utf8 *path = widechar_to_utf8(w_buffer); + free(w_buffer); + strcpy(outPath, path); + free(path); + log_verbose("outPath + subDirectory = '%s'", buffer); +} + +void platform_show_messagebox(char *message) +{ + STUB(); + log_warning(message); +} + +/** + * + * rct2: 0x004080EA + */ +int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) +{ + STUB(); + return 0; +} + +utf8 *platform_open_directory_browser(utf8 *title) +{ + STUB(); + return NULL; +} + +uint16 platform_get_locale_language(){ + /* + CHAR langCode[4]; + + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_SABBREVLANGNAME, + (LPSTR)&langCode, + sizeof(langCode)) == 0){ + return LANGUAGE_UNDEFINED; + } + + if (strcmp(langCode, "ENG") == 0){ + return LANGUAGE_ENGLISH_UK; + } + else if (strcmp(langCode, "ENU") == 0){ + return LANGUAGE_ENGLISH_US; + } + else if (strcmp(langCode, "DEU") == 0){ + return LANGUAGE_GERMAN; + } + else if (strcmp(langCode, "NLD") == 0){ + return LANGUAGE_DUTCH; + } + else if (strcmp(langCode, "FRA") == 0){ + return LANGUAGE_FRENCH; + } + else if (strcmp(langCode, "HUN") == 0){ + return LANGUAGE_HUNGARIAN; + } + else if (strcmp(langCode, "PLK") == 0){ + return LANGUAGE_POLISH; + } + else if (strcmp(langCode, "ESP") == 0){ + return LANGUAGE_SPANISH; + } + else if (strcmp(langCode, "SVE") == 0){ + return LANGUAGE_SWEDISH; + } + else if (strcmp(langCode, "ITA") == 0){ + return LANGUAGE_ITALIAN; + } + else if (strcmp(langCode, "POR") == 0){ + return LANGUAGE_PORTUGUESE_BR; + } + */ + STUB(); + return LANGUAGE_ENGLISH_UK; +} + +time_t platform_file_get_modified_time(const utf8* path){ + /* + WIN32_FILE_ATTRIBUTE_DATA data; + if (!GetFileAttributesEx(path, GetFileExInfoStandard, &data)) + return 0; + ULARGE_INTEGER ull; + ull.LowPart = data.ftLastWriteTime.dwLowDateTime; + ull.HighPart = data.ftLastWriteTime.dwHighDateTime; + return ull.QuadPart / 10000000ULL - 11644473600ULL; + */ + STUB(); + return 100; +} + +uint8 platform_get_locale_currency(){ + /* + CHAR currCode[4]; + + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_SINTLSYMBOL, + (LPSTR)&currCode, + sizeof(currCode)) == 0){ + return CURRENCY_POUNDS; + } + if (strcmp(currCode, "GBP") == 0){ + return CURRENCY_POUNDS; + } + else if (strcmp(currCode, "USD") == 0){ + return CURRENCY_DOLLARS; + } + else if (strcmp(currCode, "EUR") == 0){ + return CURRENCY_EUROS; + } + else if (strcmp(currCode, "SEK") == 0){ + return CURRENCY_KRONA; + } + else if (strcmp(currCode, "DEM") == 0){ + return CURRENCY_DEUTSCHMARK; + } + else if (strcmp(currCode, "ITL") == 0){ + return CURRENCY_LIRA; + } + else if (strcmp(currCode, "JPY") == 0){ + return CURRENCY_YEN; + } + else if (strcmp(currCode, "ESP") == 0){ + return CURRENCY_PESETA; + } + else if (strcmp(currCode, "FRF") == 0){ + return CURRENCY_FRANC; + } + else if (strcmp(currCode, "NLG") == 0){ + return CURRENCY_GUILDERS; + } + */ + STUB(); + return CURRENCY_POUNDS; +} + +uint8 platform_get_locale_measurement_format(){ + /* + UINT measurement_system; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, + (LPSTR)&measurement_system, + sizeof(measurement_system)) == 0){ + return MEASUREMENT_FORMAT_IMPERIAL; + } + switch (measurement_system){ + case 0: + return MEASUREMENT_FORMAT_METRIC; + case 1: + default: + return MEASUREMENT_FORMAT_IMPERIAL; + }*/ + STUB(); + return MEASUREMENT_FORMAT_METRIC; +} + +uint8 platform_get_locale_temperature_format(){ + /* + // There does not seem to be a function to obtain this, just check the countries + UINT country; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, + (LPSTR)&country, + sizeof(country)) == 0){ + return TEMPERATURE_FORMAT_C; + } + switch (country){ + case CTRY_UNITED_STATES: + case CTRY_BELIZE: + return TEMPERATURE_FORMAT_F; + default: + return TEMPERATURE_FORMAT_C; + } + */ + STUB(); + return TEMPERATURE_FORMAT_C; +} +#endif // __linux diff --git a/src/platform/platform.h b/src/platform/platform.h index 23934c5661..a894264f77 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -147,6 +147,7 @@ uint8 platform_get_locale_temperature_format(); #define _strcmpi _stricmp #define _stricmp(x, y) strcasecmp((x), (y)) #define _strnicmp(x, y, n) strncasecmp((x), (y), (n)) +#define _strdup(x) strdup((x)) #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define RCT2_ENDIANESS __ORDER_LITTLE_ENDIAN__ diff --git a/src/platform/unix.c b/src/platform/unix.c index e5151df42d..602709bb63 100644 --- a/src/platform/unix.c +++ b/src/platform/unix.c @@ -1,9 +1,9 @@ /***************************************************************************** * Copyright (c) 2014 Ted John * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * + * * This file is part of OpenRCT2. - * + * * OpenRCT2 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -31,14 +31,16 @@ // { // if (cmdline_run(argv, argc)) // openrct2_launch(); -// +// // return gExitCode; // } +/* char platform_get_path_separator() { return '/'; } +*/ #endif -#endif \ No newline at end of file +#endif diff --git a/src/rct2.h b/src/rct2.h index 5749e3a133..74cf311b7e 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -1,9 +1,9 @@ /***************************************************************************** * Copyright (c) 2014 Ted John * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * + * * This file is part of OpenRCT2. - * + * * OpenRCT2 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ - + #ifndef _RCT2_H_ #define _RCT2_H_ @@ -206,7 +206,11 @@ enum { // rct2 @ 0x0097F67C static const char * const file_paths[] = { - "Data\\G1.DAT", +#ifdef _WIN32 + "data\\g1.dat", +#else + "data/g1.dat", +#endif // _WIN32 "Data\\PLUGIN.DAT", "Data\\CSS1.DAT", "Data\\CSS2.DAT",