diff --git a/data/language/english_uk.txt b/data/language/english_uk.txt
index ac2dad12af..f08a5cfc68 100644
--- a/data/language/english_uk.txt
+++ b/data/language/english_uk.txt
@@ -2710,9 +2710,9 @@ STR_2704 :???
STR_2705 :???
STR_2706 :???
STR_2707 :???
-STR_2708 :???
-STR_2709 :???
-STR_2710 :???
+STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}?
+STR_2709 :Overwrite
+STR_2710 :Type the name of the file.
STR_2711 :;
STR_2712 :=
STR_2713 :,
diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj
index 5944dcba2e..ea978e0d9a 100644
--- a/projects/openrct2.vcxproj
+++ b/projects/openrct2.vcxproj
@@ -94,6 +94,7 @@
+
diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters
index 657a0d8858..f051e825df 100644
--- a/projects/openrct2.vcxproj.filters
+++ b/projects/openrct2.vcxproj.filters
@@ -330,7 +330,6 @@
Source
-
Source\World
@@ -359,7 +358,7 @@
Source\Windows
-
+
Source\Ride
@@ -425,6 +424,9 @@
Source
+
+ Source\Windows
+
diff --git a/src/config.c b/src/config.c
index f1e91ddf38..6b6f479877 100644
--- a/src/config.c
+++ b/src/config.c
@@ -301,6 +301,12 @@ void config_apply_to_old_addresses()
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) = configFlags;
}
+static void config_get_path(char *outPath)
+{
+ platform_get_user_directory(outPath, NULL);
+ strcat(outPath, "config.ini");
+}
+
/**
* Initialise the settings.
* It checks if the OpenRCT2 folder exists and creates it if it does not
@@ -308,44 +314,35 @@ void config_apply_to_old_addresses()
*/
void config_load()
{
- char *path = platform_get_orct2_homefolder();
- FILE* fp;
+ FILE *fp;
+ char configPath[MAX_PATH];
+
+ config_get_path(configPath);
memcpy(&gGeneral_config, &gGeneral_config_default, sizeof(general_configuration_t));
- if (strcmp(path, "") != 0){
- if (!platform_ensure_directory_exists(path)) {
- config_error("Could not create config file (do you have write access to your documents folder?)");
+ fp = fopen(configPath, "r");
+ if (fp == NULL) {
+ config_create_default(configPath);
+ fp = fopen(configPath, "r");
+ if (fp == NULL) {
+ config_error("Could not create config file.");
return;
}
-
- sprintf(path, "%s%c%s", path, platform_get_path_separator(), "config.ini");
-
- fp = fopen(path, "r");
- if (!fp) {
- config_create_default(path);
- fp = fopen(path, "r");
- if (!fp)
- config_error("Could not create config file");
- }
-
- config_parse_settings(fp);
-
- fclose(fp);
}
- free(path);
+ config_parse_settings(fp);
+ fclose(fp);
config_apply_to_old_addresses();
}
void config_save()
{
- char *configIniPath = platform_get_orct2_homefolder();;
-
- sprintf(configIniPath, "%s%c%s", configIniPath, platform_get_path_separator(), "config.ini");
- config_save_ini(configIniPath);
+ char configPath[MAX_PATH];
+ config_get_path(configPath);
+ config_save_ini(configPath);
config_apply_to_old_addresses();
}
diff --git a/src/game.c b/src/game.c
index 568d4b2a81..9d21b3bb08 100644
--- a/src/game.c
+++ b/src/game.c
@@ -541,6 +541,9 @@ static int open_load_game_dialog()
*/
static void load_landscape()
{
+ window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE);
+ return;
+
if (open_landscape_file_dialog() == 0) {
gfx_invalidate_screen();
} else {
@@ -704,6 +707,9 @@ void sub_69E9A7()
*/
static void load_game()
{
+ window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME);
+ return;
+
if (open_load_game_dialog() == 0) {
gfx_invalidate_screen();
} else {
@@ -758,6 +764,9 @@ static int show_save_game_dialog(char *resultPath)
char save_game()
{
+ window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME);
+ return 0;
+
char path[256];
if (!show_save_game_dialog(path)) {
diff --git a/src/interface/screenshot.c b/src/interface/screenshot.c
index b44a3cc0f9..9616dae9ae 100644
--- a/src/interface/screenshot.c
+++ b/src/interface/screenshot.c
@@ -70,10 +70,10 @@ void screenshot_check()
static int screenshot_get_next_path(char *path, int format)
{
- char *screenshotPath = platform_get_orct2_homesubfolder("screenshot");
- if (!platform_ensure_directory_exists(screenshotPath)) {
- free(screenshotPath);
+ char screenshotPath[MAX_PATH];
+ platform_get_user_directory(screenshotPath, "screenshot");
+ if (!platform_ensure_directory_exists(screenshotPath)) {
fprintf(stderr, "Unable to save screenshots in OpenRCT2 screenshot directory.\n");
return -1;
}
@@ -83,14 +83,14 @@ static int screenshot_get_next_path(char *path, int format)
RCT2_GLOBAL(0x013CE952, uint16) = i;
// Glue together path and filename
- sprintf(path, "%s%cSCR%d%s", screenshotPath, platform_get_path_separator(), i, _screenshot_format_extension[format]);
+ sprintf(path, "%sSCR%d%s", screenshotPath, i, _screenshot_format_extension[format]);
if (!platform_file_exists(path)) {
return i;
}
}
- free(screenshotPath);
+ fprintf(stderr, "You have too many saved screenshots.\n");
return -1;
}
diff --git a/src/interface/window.c b/src/interface/window.c
index 69b9ca1b44..5c3c0c4d86 100644
--- a/src/interface/window.c
+++ b/src/interface/window.c
@@ -457,6 +457,15 @@ rct_window *window_create_auto_pos(int width, int height, uint32 *event_handlers
return (rct_window*)esi;
}
+rct_window *window_create_centred(int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags)
+{
+ int x, y;
+
+ x = (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - width) / 2;
+ y = (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height) / 2;
+ return window_create(x, y, width, height, event_handlers, cls, flags);
+}
+
/**
* Closes the specified window.
* rct2: 0x006ECD4C
@@ -479,6 +488,8 @@ void window_close(rct_window* window)
RCT2_CALLPROC_X(window->event_handlers[WE_CLOSE], 0, 0, 0, 0, (int)window, 0, 0);
window = window_find_by_number(cls, number);
+ if (window == NULL)
+ return;
// Remove viewport
if (window->viewport != NULL) {
diff --git a/src/interface/window.h b/src/interface/window.h
index dacc55a0b4..744c6f9618 100644
--- a/src/interface/window.h
+++ b/src/interface/window.h
@@ -398,7 +398,9 @@ enum {
WC_RESEARCH = 111,
WC_VIEWPORT = 112,
WC_TEXTINPUT = 113,
- WC_MAPGEN = 114
+ WC_MAPGEN = 114,
+ WC_LOADSAVE = 115,
+ WC_LOADSAVE_OVERWRITE_PROMPT = 116
} WINDOW_CLASS;
enum PROMPT_MODE {
@@ -416,6 +418,15 @@ typedef enum {
BTM_TB_DIRTY_FLAG_PARK_RATING = (1 << 4)
} BTM_TOOLBAR_DIRTY_FLAGS;
+enum {
+ LOADSAVETYPE_LOAD = 0 << 0,
+ LOADSAVETYPE_SAVE = 1 << 0,
+
+ LOADSAVETYPE_GAME = 0 << 1,
+ LOADSAVETYPE_LANDSCAPE = 1 << 1,
+ LOADSAVETYPE_SCENARIO = 2 << 1
+};
+
// rct2: 0x01420078
extern rct_window* g_window_list;
@@ -427,6 +438,7 @@ void window_dispatch_update_all();
void window_update_all();
rct_window *window_create(int x, int y, int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags);
rct_window *window_create_auto_pos(int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags);
+rct_window *window_create_centred(int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags);
void window_close(rct_window *window);
void window_close_by_class(rct_windowclass cls);
void window_close_by_number(rct_windowclass cls, rct_windownumber number);
@@ -538,6 +550,7 @@ void window_track_manage_open();
void window_viewport_open();
void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id title, rct_string_id description, rct_string_id existing_text, uint32 existing_args, int maxLength);
rct_window *window_mapgen_open();
+rct_window *window_loadsave_open(int type);
void window_editor_main_open();
void window_editor_bottom_toolbar_open();
diff --git a/src/localisation/localisation.c b/src/localisation/localisation.c
index a0ae867d76..f8dca641b0 100644
--- a/src/localisation/localisation.c
+++ b/src/localisation/localisation.c
@@ -590,7 +590,9 @@ void format_string_part_from_raw(char **dest, const char *src, char **args)
void format_string_part(char **dest, rct_string_id format, char **args)
{
- if (format < 0x8000) {
+ if (format == (rct_string_id)STR_NONE) {
+ **dest = 0;
+ } else if (format < 0x8000) {
// Language string
format_string_part_from_raw(dest, language_get_string(format), args);
} else if (format < 0x9000) {
diff --git a/src/object_list.c b/src/object_list.c
index abb7ef2278..8ecf62044b 100644
--- a/src/object_list.c
+++ b/src/object_list.c
@@ -87,11 +87,10 @@ static int object_list_cache_save(int fileCount, uint64 totalFileSize, int fileD
void object_list_create_hash_table();
static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* installed_entry, const char* path);
-static void get_plugin_path(char *path)
+static void get_plugin_path(char *outPath)
{
- char *homePath = platform_get_orct2_homefolder();
- sprintf(path, "%s%c%s", homePath, platform_get_path_separator(), "plugin.dat");
- free(homePath);
+ platform_get_user_directory(outPath, NULL);
+ strcat(outPath, "plugin.dat");
}
static void object_list_sort()
diff --git a/src/openrct2.c b/src/openrct2.c
index 98d0c49375..5775af2b34 100644
--- a/src/openrct2.c
+++ b/src/openrct2.c
@@ -38,11 +38,69 @@ int _finished;
static void openrct2_loop();
+static void openrct2_copy_files_over(const char *originalDirectory, const char *newDirectory, const char *extension)
+{
+ char *ch, filter[MAX_PATH], oldPath[MAX_PATH], newPath[MAX_PATH];
+ int fileEnumHandle;
+ file_info fileInfo;
+
+ if (!platform_ensure_directory_exists(newDirectory)) {
+ log_error("Could not create directory %s.", newDirectory);
+ return;
+ }
+
+ // Create filter path
+ strcpy(filter, originalDirectory);
+ ch = strchr(filter, '*');
+ if (ch != NULL)
+ *ch = 0;
+ strcat(filter, "*");
+ strcat(filter, extension);
+
+ fileEnumHandle = platform_enumerate_files_begin(filter);
+ while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) {
+ strcpy(newPath, newDirectory);
+ strcat(newPath, fileInfo.path);
+
+ strcpy(oldPath, originalDirectory);
+ ch = strchr(oldPath, '*');
+ if (ch != NULL)
+ *ch = 0;
+ strcat(oldPath, fileInfo.path);
+
+ if (!platform_file_exists(newPath))
+ platform_file_copy(oldPath, newPath);
+ }
+ platform_enumerate_files_end(fileEnumHandle);
+}
+
+/**
+ * Copy saved games and landscapes to user directory
+ */
+static void openrct2_copy_original_user_files_over()
+{
+ char path[MAX_PATH];
+
+ platform_get_user_directory(path, "save");
+ openrct2_copy_files_over((char*)RCT2_ADDRESS_SAVED_GAMES_PATH, path, ".sv6");
+
+ platform_get_user_directory(path, "landscape");
+ openrct2_copy_files_over((char*)RCT2_ADDRESS_LANDSCAPES_PATH, path, ".sc6");
+}
+
/**
* Launches the game, after command line arguments have been parsed and processed.
*/
void openrct2_launch()
{
+ char userPath[MAX_PATH];
+
+ platform_get_user_directory(userPath, NULL);
+ if (!platform_ensure_directory_exists(userPath)) {
+ log_fatal("Could not create user directory (do you have write access to your documents folder?)");
+ return;
+ }
+
config_load();
// TODO add configuration option to allow multiple instances
@@ -59,6 +117,8 @@ void openrct2_launch()
if (!rct2_init())
return;
+ openrct2_copy_original_user_files_over();
+
Mixer_Init(NULL);
switch (gOpenRCT2StartupAction) {
diff --git a/src/platform/platform.h b/src/platform/platform.h
index 1ceead246a..f7fe484a2d 100644
--- a/src/platform/platform.h
+++ b/src/platform/platform.h
@@ -77,7 +77,6 @@ void platform_update_palette(char* colours, int start_index, int num_colours);
void platform_set_fullscreen_mode(int mode);
void platform_set_cursor(char cursor);
void platform_process_messages();
-char *platform_get_orct2_homesubfolder();
int platform_scancode_to_rct_keycode(int sdl_key);
void platform_start_text_input(char* buffer, int max_length);
void platform_stop_text_input();
@@ -91,6 +90,7 @@ int platform_lock_single_instance();
int platform_enumerate_files_begin(const char *pattern);
int platform_enumerate_files_next(int handle, file_info *outFileInfo);
void platform_enumerate_files_end(int handle);
+int platform_file_copy(const char *srcPath, const char *dstPath);
int platform_file_move(const char *srcPath, const char *dstPath);
int platform_file_delete(const char *path);
void platform_hide_cursor();
@@ -98,7 +98,7 @@ void platform_show_cursor();
void platform_get_cursor_position(int *x, int *y);
void platform_set_cursor_position(int x, int y);
unsigned int platform_get_ticks();
-char *platform_get_orct2_homefolder();
+void platform_get_user_directory(char *outPath, const char *subDirectory);
void platform_show_messagebox(char *message);
int platform_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName);
char *platform_open_directory_browser(char *title);
diff --git a/src/platform/shared.c b/src/platform/shared.c
index 01ca5114db..9e0053d686 100644
--- a/src/platform/shared.c
+++ b/src/platform/shared.c
@@ -569,16 +569,6 @@ void platform_set_fullscreen_mode(int mode)
}
}
-char *platform_get_orct2_homesubfolder(const char *subFolder)
-{
- char seperator = platform_get_path_separator();
-
- char *path = platform_get_orct2_homefolder();
- strcat(path, &seperator);
- strcat(path, subFolder);
- return path;
-}
-
/**
* This is not quite the same as the below function as we don't want to
* derfererence the cursor before the function.
diff --git a/src/platform/windows.c b/src/platform/windows.c
index 308b75e050..6fcb019e68 100644
--- a/src/platform/windows.c
+++ b/src/platform/windows.c
@@ -192,6 +192,11 @@ void platform_enumerate_files_end(int handle)
enumFileInfo->active = 0;
}
+int platform_file_copy(const char *srcPath, const char *dstPath)
+{
+ return CopyFileA(srcPath, dstPath, TRUE);
+}
+
int platform_file_move(const char *srcPath, const char *dstPath)
{
return MoveFileA(srcPath, dstPath);
@@ -235,21 +240,21 @@ unsigned int platform_get_ticks()
return GetTickCount();
}
-char* platform_get_orct2_homefolder()
+void platform_get_user_directory(char *outPath, const char *subDirectory)
{
- char *path = NULL;
- path = malloc(sizeof(char) * MAX_PATH);
- if (path == NULL){
- log_fatal("Error allocating memory!");
- exit(EXIT_FAILURE);
+ char seperator[2] = { platform_get_path_separator(), 0 };
+
+ if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, outPath))) {
+ strcat(outPath, seperator);
+ strcat(outPath, "OpenRCT2");
+ strcat(outPath, seperator);
+ if (subDirectory != NULL && subDirectory[0] != 0) {
+ strcat(outPath, subDirectory);
+ strcat(outPath, seperator);
+ }
+ } else {
+ outPath[0] = 0;
}
-
- path[0] = '\0';
-
- if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, path)))
- strcat(path, "\\OpenRCT2");
-
- return path;
}
void platform_show_messagebox(char *message)
diff --git a/src/ride/track.c b/src/ride/track.c
index 0207b387b0..f8b1780070 100644
--- a/src/ride/track.c
+++ b/src/ride/track.c
@@ -234,11 +234,10 @@ uint32* sub_6AB49A(rct_object_entry* entry){
return (((uint32*)object_get_next(object_list_entry)) - 1);
}
-static void get_track_idx_path(char *path)
+static void get_track_idx_path(char *outPath)
{
- char *homePath = platform_get_orct2_homefolder();
- sprintf(path, "%s%c%s", homePath, platform_get_path_separator(), "tracks.idx");
- free(homePath);
+ platform_get_user_directory(outPath, NULL);
+ strcat(outPath, "tracks.idx");
}
static void track_list_query_directory(int *outTotalFiles){
diff --git a/src/scenario_list.c b/src/scenario_list.c
index a05868efb9..eb2cc8fb24 100644
--- a/src/scenario_list.c
+++ b/src/scenario_list.c
@@ -156,9 +156,8 @@ static int scenario_list_sort_compare(const void *a, const void *b)
*/
static void scenario_scores_get_path(char *outPath)
{
- char *homePath = platform_get_orct2_homefolder();
- sprintf(outPath, "%s%c%s", homePath, platform_get_path_separator(), "scores.dat");
- free(homePath);
+ platform_get_user_directory(outPath, NULL);
+ strcat(outPath, "scores.dat");
}
/**
diff --git a/src/windows/editor_bottom_toolbar.c b/src/windows/editor_bottom_toolbar.c
index 934b6e0920..0dce89ebbe 100644
--- a/src/windows/editor_bottom_toolbar.c
+++ b/src/windows/editor_bottom_toolbar.c
@@ -299,6 +299,10 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario()
}
window_close_all();
+
+ window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO);
+ return;
+
if (!show_save_scenario_dialog(path)) {
gfx_invalidate_screen();
return;
diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c
new file mode 100644
index 0000000000..8d51cfdec9
--- /dev/null
+++ b/src/windows/loadsave.c
@@ -0,0 +1,605 @@
+/*****************************************************************************
+* 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 .
+*****************************************************************************/
+
+#include "../addresses.h"
+#include "../config.h"
+#include "../game.h"
+#include "../editor.h"
+#include "../interface/widget.h"
+#include "../interface/window.h"
+#include "../localisation/localisation.h"
+#include "../platform/platform.h"
+#include "../scenario.h"
+#include "../title.h"
+#include "../windows/error.h"
+
+#pragma region Widgets
+
+#define WW 340
+#define WH 400
+
+enum {
+ WIDX_BACKGROUND,
+ WIDX_TITLE,
+ WIDX_CLOSE,
+ WIDX_SCROLL
+};
+
+// 0x9DE48C
+static rct_widget window_loadsave_widgets[] = {
+ { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE },
+ { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_NONE, STR_WINDOW_TITLE_TIP },
+ { WWT_CLOSEBOX, 0, WW-13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP },
+ { WWT_SCROLL, 0, 4, WW - 5, 18, WH - 18, 2, STR_NONE },
+ { WIDGETS_END }
+};
+
+#pragma endregion
+
+#pragma region Events
+
+void window_loadsave_emptysub() { }
+static void window_loadsave_close();
+static void window_loadsave_mouseup();
+static void window_loadsave_update(rct_window *w);
+static void window_loadsave_scrollgetsize();
+static void window_loadsave_scrollmousedown();
+static void window_loadsave_scrollmouseover();
+static void window_loadsave_textinput();
+static void window_loadsave_tooltip();
+static void window_loadsave_paint();
+static void window_loadsave_scrollpaint();
+
+static void* window_loadsave_events[] = {
+ window_loadsave_close,
+ window_loadsave_mouseup,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_update,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_scrollgetsize,
+ window_loadsave_scrollmousedown,
+ window_loadsave_emptysub,
+ window_loadsave_scrollmouseover,
+ window_loadsave_textinput,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_tooltip,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_emptysub,
+ window_loadsave_paint,
+ window_loadsave_scrollpaint
+};
+
+#pragma endregion
+
+typedef struct {
+ char name[256];
+ char path[MAX_PATH];
+} loadsave_list_item;
+
+int _listItemsCount = 0;
+loadsave_list_item *_listItems = NULL;
+char _directory[MAX_PATH];
+char _extension[32];
+int _loadsaveType;
+
+static void window_loadsave_populate_list(int includeNewItem, const char *directory, const char *extension);
+static void window_loadsave_select(rct_window *w, const char *path);
+
+static rct_window *window_overwrite_prompt_open(const char *name, const char *path);
+
+rct_window *window_loadsave_open(int type)
+{
+ char path[MAX_PATH], *ch;
+ int includeNewItem;
+ rct_window* w;
+
+ w = window_bring_to_front_by_class(WC_LOADSAVE);
+ if (w == NULL) {
+ w = window_create_centred(WW, WH, (uint32*)window_loadsave_events, WC_LOADSAVE, WF_STICK_TO_FRONT);
+ w->widgets = window_loadsave_widgets;
+ w->enabled_widgets = (1 << WIDX_CLOSE);
+ window_init_scroll_widgets(w);
+ w->colours[0] = 7;
+ w->colours[1] = 7;
+ w->colours[2] = 7;
+ }
+
+ w->no_list_items = 0;
+ w->selected_list_item = -1;
+
+ _loadsaveType = type;
+ switch (type) {
+ case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME):
+ w->widgets[WIDX_TITLE].image = STR_LOAD_GAME;
+ break;
+ case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) :
+ w->widgets[WIDX_TITLE].image = STR_SAVE_GAME;
+ break;
+ case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) :
+ w->widgets[WIDX_TITLE].image = STR_LOAD_LANDSCAPE;
+ break;
+ case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) :
+ w->widgets[WIDX_TITLE].image = STR_SAVE_LANDSCAPE;
+ break;
+ case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) :
+ w->widgets[WIDX_TITLE].image = STR_SAVE_SCENARIO;
+ break;
+ }
+
+ includeNewItem = (type & 1) == LOADSAVETYPE_SAVE;
+ switch (type & 6) {
+ case LOADSAVETYPE_GAME:
+ platform_get_user_directory(path, "save");
+ if (!platform_ensure_directory_exists(path)) {
+ fprintf(stderr, "Unable to create save directory.");
+ window_close(w);
+ return NULL;
+ }
+
+ window_loadsave_populate_list(includeNewItem, path, ".sv6");
+ break;
+ case LOADSAVETYPE_LANDSCAPE:
+ platform_get_user_directory(path, "landscape");
+ if (!platform_ensure_directory_exists(path)) {
+ fprintf(stderr, "Unable to create landscapes directory.");
+ window_close(w);
+ return NULL;
+ }
+
+ window_loadsave_populate_list(includeNewItem, path, ".sc6");
+ break;
+ case LOADSAVETYPE_SCENARIO:
+ /*
+ Uncomment when user scenarios are separated
+
+ platform_get_user_directory(path, "scenario");
+ if (!platform_ensure_directory_exists(path)) {
+ fprintf(stderr, "Unable to create scenarios directory.");
+ window_close(w);
+ return NULL;
+ }
+ */
+
+ strcpy(path, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char));
+ ch = strchr(path, '*');
+ if (ch != NULL)
+ *ch = 0;
+
+ window_loadsave_populate_list(includeNewItem, path, ".sc6");
+ break;
+ }
+ w->no_list_items = _listItemsCount;
+ return w;
+}
+
+static void window_loadsave_close()
+{
+ if (_listItems != NULL) {
+ free(_listItems);
+ _listItems = NULL;
+ }
+
+ window_close_by_class(WC_LOADSAVE_OVERWRITE_PROMPT);
+}
+
+static void window_loadsave_mouseup()
+{
+ short widgetIndex;
+ rct_window *w;
+
+ window_widget_get_registers(w, widgetIndex);
+
+ switch (widgetIndex){
+ case WIDX_CLOSE:
+ window_close(w);
+ break;
+ }
+}
+
+static void window_loadsave_update(rct_window *w)
+{
+
+}
+
+static void window_loadsave_scrollgetsize()
+{
+ rct_window *w;
+ int width, height;
+
+ window_get_register(w);
+
+ width = 0;
+ height = w->no_list_items * 10;
+
+ window_scrollsize_set_registers(width, height);
+}
+
+static void window_loadsave_scrollmousedown()
+{
+ int selectedItem;
+ short x, y, scrollIndex;
+ rct_window *w;
+
+ window_scrollmouse_get_registers(w, scrollIndex, x, y);
+
+ selectedItem = y / 10;
+ if (selectedItem >= w->no_list_items)
+ return;
+
+ // Load or overwrite
+ if (_listItems[selectedItem].path[0] == 0) {
+ rct_string_id templateStringId = 3165;
+ char *templateString;
+
+ templateString = (char*)language_get_string(templateStringId);
+ strcpy(templateString, (char*)RCT2_ADDRESS_SCENARIO_NAME);
+ window_text_input_open(w, WIDX_SCROLL, STR_NONE, 2710, templateStringId, 0, 64);
+ } else {
+ if ((_loadsaveType & 1) == LOADSAVETYPE_SAVE)
+ window_overwrite_prompt_open(_listItems[selectedItem].name, _listItems[selectedItem].path);
+ else
+ window_loadsave_select(w, _listItems[selectedItem].path);
+ }
+}
+
+static void window_loadsave_scrollmouseover()
+{
+ int selectedItem;
+ short x, y, scrollIndex;
+ rct_window *w;
+
+ window_scrollmouse_get_registers(w, scrollIndex, x, y);
+
+ selectedItem = y / 10;
+ if (selectedItem >= w->no_list_items)
+ return;
+
+ w->selected_list_item = selectedItem;
+
+ window_invalidate(w);
+}
+
+static void window_loadsave_textinput()
+{
+ rct_window *w;
+ short widgetIndex;
+ uint8 result;
+ char *text, path[MAX_PATH];
+ int i, overwrite;
+
+ window_textinput_get_registers(w, widgetIndex, result, text);
+
+ if (!result || text[0] == 0)
+ return;
+
+ strncpy(path, _directory, sizeof(path));
+ strncat(path, text, sizeof(path));
+ strncat(path, _extension, sizeof(path));
+
+ overwrite = 0;
+ for (i = 0; i < _listItemsCount; i++) {
+ if (_stricmp(_listItems[i].path, path) == 0) {
+ overwrite = 1;
+ break;
+ }
+ }
+
+ if (overwrite)
+ window_overwrite_prompt_open(text, path);
+ else
+ window_loadsave_select(w, path);
+}
+
+static void window_loadsave_tooltip()
+{
+ RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST;
+}
+
+static void window_loadsave_paint()
+{
+ rct_window *w;
+ rct_drawpixelinfo *dpi;
+
+ window_paint_get_registers(w, dpi);
+
+ window_draw_widgets(w, dpi);
+}
+
+static void window_loadsave_scrollpaint()
+{
+ int i, y;
+ rct_window *w;
+ rct_drawpixelinfo *dpi;
+ rct_string_id stringId, templateStringId = 3165;
+ char *templateString;
+
+ window_paint_get_registers(w, dpi);
+
+ gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, RCT2_ADDRESS(0x0141FC48,uint8)[w->colours[1] * 8]);
+
+ templateString = (char*)language_get_string(templateStringId);
+ for (i = 0; i < w->no_list_items; i++) {
+ y = i * 10;
+ if (y > dpi->y + dpi->height)
+ break;
+
+ if (y + 10 < dpi->y)
+ continue;
+
+ stringId = STR_BLACK_STRING;
+ if (i == w->selected_list_item) {
+ stringId = STR_WINDOW_COLOUR_2_STRING;
+ gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x2000031);
+ }
+
+ strcpy(templateString, _listItems[i].name);
+ gfx_draw_string_left(dpi, stringId, &templateStringId, 0, 0, y - 1);
+ }
+}
+
+static void window_loadsave_populate_list(int includeNewItem, const char *directory, const char *extension)
+{
+ int i, listItemCapacity, fileEnumHandle;
+ file_info fileInfo;
+ loadsave_list_item *listItem;
+ const char *src;
+ char *dst, filter[MAX_PATH];
+
+ strncpy(_directory, directory, sizeof(_directory));
+ strncpy(_extension, extension, sizeof(_extension));
+
+ strncpy(filter, directory, sizeof(filter));
+ strncat(filter, "*", sizeof(filter));
+ strncat(filter, extension, sizeof(filter));
+
+ if (_listItems != NULL)
+ free(_listItems);
+
+ listItemCapacity = 8;
+ _listItems = (loadsave_list_item*)malloc(listItemCapacity * sizeof(loadsave_list_item));
+ _listItemsCount = 0;
+
+ if (includeNewItem) {
+ listItem = &_listItems[_listItemsCount];
+ strncpy(listItem->name, "(new file)", sizeof(listItem->name));
+ listItem->path[0] = 0;
+ _listItemsCount++;
+ }
+
+ fileEnumHandle = platform_enumerate_files_begin(filter);
+ while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) {
+ if (listItemCapacity <= _listItemsCount) {
+ listItemCapacity *= 2;
+ _listItems = realloc(_listItems, listItemCapacity * sizeof(loadsave_list_item));
+ }
+
+ listItem = &_listItems[_listItemsCount];
+ strncpy(listItem->path, directory, sizeof(listItem->path));
+ strncat(listItem->path, fileInfo.path, sizeof(listItem->path));
+
+ src = fileInfo.path;
+ dst = listItem->name;
+ i = 0;
+ while (*src != 0 && *src != '.' && i < sizeof(listItem->name) - 1) {
+ *dst++ = *src++;
+ i++;
+ }
+ *dst = 0;
+
+ _listItemsCount++;
+ }
+ platform_enumerate_files_end(fileEnumHandle);
+}
+
+static void window_loadsave_select(rct_window *w, const char *path)
+{
+ switch (_loadsaveType) {
+ case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME):
+ if (game_load_save(path)) {
+ window_close(w);
+ gfx_invalidate_screen();
+ rct2_endupdate();
+ } else {
+ // 1050, not the best message...
+ window_error_open(STR_LOAD_GAME, 1050);
+ }
+ break;
+ case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME):
+ if (scenario_save((char*)path, gGeneral_config.save_plugin_data ? 1 : 0)) {
+ window_close(w);
+
+ game_do_command(0, 1047, 0, -1, GAME_COMMAND_0, 0, 0);
+ gfx_invalidate_screen();
+ } else {
+ window_error_open(STR_SAVE_GAME, 1047);
+ }
+ break;
+ case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) :
+ editor_load_landscape(path);
+ if (1) {
+ gfx_invalidate_screen();
+ rct2_endupdate();
+ } else {
+ // 1050, not the best message...
+ window_error_open(STR_LOAD_LANDSCAPE, 1050);
+ }
+ break;
+ case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE):
+ if (scenario_save((char*)path, gGeneral_config.save_plugin_data ? 3 : 2)) {
+ window_close(w);
+ gfx_invalidate_screen();
+ } else {
+ window_error_open(STR_SAVE_LANDSCAPE, 1049);
+ }
+ break;
+ case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO):
+ {
+ rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
+ int parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32);
+ RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18;
+ s6Info->var_000 = 255;
+ int success = scenario_save((char*)path, gGeneral_config.save_plugin_data ? 3 : 2);
+ RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup;
+
+ if (success) {
+ window_close(w);
+ title_load();
+ } else {
+ window_error_open(STR_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED);
+ s6Info->var_000 = 4;
+ }
+ }
+ break;
+ }
+}
+
+#pragma region Overwrite prompt
+
+#define OVERWRITE_WW 200
+#define OVERWRITE_WH 100
+
+enum {
+ WIDX_OVERWRITE_BACKGROUND,
+ WIDX_OVERWRITE_TITLE,
+ WIDX_OVERWRITE_CLOSE,
+ WIDX_OVERWRITE_OVERWRITE,
+ WIDX_OVERWRITE_CANCEL
+};
+
+static rct_widget window_overwrite_prompt_widgets[] = {
+ { WWT_FRAME, 0, 0, OVERWRITE_WW - 1, 0, OVERWRITE_WH - 1, STR_NONE, STR_NONE },
+ { WWT_CAPTION, 0, 1, OVERWRITE_WW - 2, 1, 14, 2709, STR_WINDOW_TITLE_TIP },
+ { WWT_CLOSEBOX, 0, OVERWRITE_WW - 13, OVERWRITE_WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP },
+ { WWT_DROPDOWN_BUTTON, 0, 10, 94, OVERWRITE_WH - 20, OVERWRITE_WH - 9, 2709, STR_NONE },
+ { WWT_DROPDOWN_BUTTON, 0, OVERWRITE_WW - 95, OVERWRITE_WW - 11, OVERWRITE_WH - 20, OVERWRITE_WH - 9, STR_SAVE_PROMPT_CANCEL, STR_NONE },
+ { WIDGETS_END }
+};
+
+static void window_overwrite_prompt_emptysub(){}
+static void window_overwrite_prompt_mouseup();
+static void window_overwrite_prompt_paint();
+
+static void* window_overwrite_prompt_events[] = {
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_mouseup,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_emptysub,
+ window_overwrite_prompt_paint,
+ window_overwrite_prompt_emptysub
+};
+
+static char _window_overwrite_prompt_name[256];
+static char _window_overwrite_prompt_path[MAX_PATH];
+
+static rct_window *window_overwrite_prompt_open(const char *name, const char *path)
+{
+ rct_window *w;
+
+ window_close_by_class(WC_LOADSAVE_OVERWRITE_PROMPT);
+
+ w = window_create_centred(OVERWRITE_WW, OVERWRITE_WH, (uint32*)window_overwrite_prompt_events, WC_LOADSAVE_OVERWRITE_PROMPT, WF_STICK_TO_FRONT);
+ w->widgets = window_overwrite_prompt_widgets;
+ w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_OVERWRITE_CANCEL) | (1 << WIDX_OVERWRITE_OVERWRITE);
+ window_init_scroll_widgets(w);
+ w->flags |= WF_TRANSPARENT;
+ w->colours[0] = 154;
+
+ strncpy(_window_overwrite_prompt_name, name, sizeof(_window_overwrite_prompt_name));
+ strncpy(_window_overwrite_prompt_path, path, sizeof(_window_overwrite_prompt_path));
+
+ return w;
+}
+
+static void window_overwrite_prompt_mouseup()
+{
+ short widgetIndex;
+ rct_window *w, *loadsaveWindow;
+
+ window_widget_get_registers(w, widgetIndex);
+
+ switch (widgetIndex){
+ case WIDX_OVERWRITE_OVERWRITE:
+ loadsaveWindow = window_find_by_class(WC_LOADSAVE);
+ if (loadsaveWindow != NULL)
+ window_loadsave_select(loadsaveWindow, _window_overwrite_prompt_path);
+ window_close(w);
+ break;
+ case WIDX_OVERWRITE_CANCEL:
+ case WIDX_OVERWRITE_CLOSE:
+ window_close(w);
+ }
+}
+
+static void window_overwrite_prompt_paint()
+{
+ rct_window *w;
+ rct_drawpixelinfo *dpi;
+
+ window_paint_get_registers(w, dpi);
+
+ window_draw_widgets(w, dpi);
+
+ rct_string_id templateStringId = 3165;
+ char *templateString;
+
+ templateString = (char*)language_get_string(templateStringId);
+ strcpy(templateString, _window_overwrite_prompt_name);
+
+ int x = w->x + w->width / 2;
+ int y = w->y + (w->height / 2) - 3;
+ gfx_draw_string_centred_wrapped(dpi, &templateStringId, x, y, w->width - 4, 2708, 0);
+}
+
+
+#pragma endregion
\ No newline at end of file
diff --git a/src/windows/text_input.c b/src/windows/text_input.c
index ed0d953afa..a5291e1328 100644
--- a/src/windows/text_input.c
+++ b/src/windows/text_input.c
@@ -111,7 +111,8 @@ void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id t
// Enter in the the text input buffer any existing
// text.
- format_string(text_input, existing_text, &existing_args);
+ if (existing_text != (rct_string_id)STR_NONE)
+ format_string(text_input, existing_text, &existing_args);
// This is the text displayed above the input box
input_text_description = description;
diff --git a/src/windows/top_toolbar.c b/src/windows/top_toolbar.c
index 6cb873b68b..e65ff0bb2d 100644
--- a/src/windows/top_toolbar.c
+++ b/src/windows/top_toolbar.c
@@ -396,7 +396,8 @@ static void window_top_toolbar_dropdown()
break;
case DDIDX_SAVE_GAME:
if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) {
- RCT2_CALLPROC_EBPSAFE(0x0066FE2A);
+ // RCT2_CALLPROC_EBPSAFE(0x0066FE2A);
+ window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE);
} else {
tool_cancel();
save_game();