From d9e0f8ff6adb1cf34ec02b4c798bd98f6fbeaff6 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Tue, 25 Nov 2014 02:05:48 +0000 Subject: [PATCH] implement save scenario and fix various load / save dialog issues, fixes #433 --- src/editor.c | 11 +--- src/game.c | 59 ++++++++++++++------- src/localisation/string_ids.h | 7 +++ src/platform/osinterface.c | 7 +-- src/scenario.c | 68 +++++++++++++++++++++++- src/scenario.h | 2 + src/util/util.c | 13 +++++ src/util/util.h | 1 + src/windows/editor_bottom_toolbar.c | 81 ++++++++++++++++++++++++++--- src/windows/error.c | 3 +- 10 files changed, 210 insertions(+), 42 deletions(-) diff --git a/src/editor.c b/src/editor.c index cf29c09eab..23274db7fd 100644 --- a/src/editor.c +++ b/src/editor.c @@ -121,7 +121,7 @@ static int show_convert_saved_game_to_scenario_dialog(char *resultPath) void editor_convert_save_to_scenario() { rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - char *ch, savedGamePath[MAX_PATH]; + char savedGamePath[MAX_PATH]; rct_window *w; rct_viewport *viewport; @@ -129,14 +129,7 @@ void editor_convert_save_to_scenario() if (!show_convert_saved_game_to_scenario_dialog(savedGamePath)) return; - // Ensure it ends with .SV6 - ch = savedGamePath; - while (*++ch != '.') { - if (*ch == 0) { - strcpy(ch, ".SV6"); - break; - } - } + path_set_extension(savedGamePath, ".SV6"); // Load the saved game if (!game_load_save(savedGamePath)) diff --git a/src/game.c b/src/game.c index 7820583514..e3b6682b0e 100644 --- a/src/game.c +++ b/src/game.c @@ -43,6 +43,7 @@ #include "title.h" #include "tutorial.h" #include "util/sawyercoding.h" +#include "util/util.h" #include "windows/error.h" #include "windows/tooltip.h" #include "world/climate.h" @@ -763,33 +764,51 @@ static void load_game() } } +/** + * + * rct2: 0x006750E9 + */ +static int show_save_game_dialog(char *resultPath) +{ + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + + int result; + char title[256]; + char filename[MAX_PATH]; + char filterName[256]; + + format_string(title, STR_SAVE_GAME_1040, NULL); + strcpy(filename, RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH_2, char)); + format_string(filterName, STR_RCT2_SAVED_GAME, NULL); + + pause_sounds(); + result = osinterface_open_common_file_dialog(0, title, filename, "*.SV6", filterName); + unpause_sounds(); + + if (result) + strcpy(resultPath, filename); + return result; +} + char save_game() { - int eax, ebx, ecx, edx, esi, edi, ebp; - RCT2_CALLFUNC_X(0x006750E9, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if (eax == 0) { - // user pressed "cancel" + char path[256]; + + if (!show_save_game_dialog(path)) { gfx_invalidate_screen(); return 0; } - - char *src = (char*)0x0141EF67; - do { - src++; - } while (*src != '.' && *src != '\0'); - strcpy(src, ".SV6"); - strcpy((char*) RCT2_ADDRESS_SAVED_GAMES_PATH_2, (char*) 0x0141EF68); - - eax = 0; - if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & 8) - eax |= 1; - RCT2_CALLPROC_X(0x006754F5, eax, 0, 0, 0, 0, 0, 0); - // check success? - game_do_command(0, 1047, 0, -1, GAME_COMMAND_0, 0, 0); - gfx_invalidate_screen(); + // Ensure path has .SV6 extension + path_set_extension(path, ".SV6"); - return 1; + if (scenario_save(path, gGeneral_config.save_plugin_data ? 1 : 0)) { + game_do_command(0, 1047, 0, -1, GAME_COMMAND_0, 0, 0); + gfx_invalidate_screen(); + return 1; + } else { + return 0; + } } /** diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index deaf43dbdc..02ca95a1a7 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -185,8 +185,13 @@ enum { STR_LOAD_LANDSCAPE_DIALOG_TITLE = 1037, STR_CONVERT_SAVED_GAME_TO_SCENARIO_1038 = 1038, + STR_SAVE_GAME_1040 = 1040, + STR_SAVE_SCENARIO = 1041, + STR_RCT2_SAVED_GAME = 1043, + STR_RCT2_SCENARIO_FILE = 1044, STR_RCT2_LANDSCAPE_FILE = 1045, + STR_SCENARIO_SAVE_FAILED = 1048, STR_INVISIBLE_SUPPORTS = 1051, STR_INVISIBLE_PEOPLE = 1052, @@ -1203,6 +1208,8 @@ enum { STR_NO_DETAILS_YET = 3317, + STR_UNABLE_TO_SAVE_SCENARIO_FILE = 3320, + STR_OBJECTIVE = 3322, STR_CANT_ADVANCE_TO_NEXT_EDITOR_STAGE = 3328, diff --git a/src/platform/osinterface.c b/src/platform/osinterface.c index 4cb965ce22..9e5f2eb0e7 100644 --- a/src/platform/osinterface.c +++ b/src/platform/osinterface.c @@ -795,15 +795,16 @@ int osinterface_open_common_file_dialog(int type, char *title, char *filename, c // Get directory path from given filename strcpy(initialDirectory, filename); - dotAddress = strrchr(filename, '.'); + dotAddress = strrchr(initialDirectory, '.'); if (dotAddress != NULL) { - slashAddress = strrchr(filename, '\\'); + slashAddress = strrchr(initialDirectory, '\\'); if (slashAddress < dotAddress) *(slashAddress + 1) = 0; } // Clear filename - *filename = 0; + if (type != 0) + *filename = 0; // Set open file name options memset(&openFileName, 0, sizeof(OPENFILENAME)); diff --git a/src/scenario.c b/src/scenario.c index dca1f02353..95729b4e7a 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -45,6 +45,8 @@ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *in { FILE *file; + log_verbose("loading scenario details, %s", path); + file = fopen(path, "rb"); if (file != NULL) { // Read first chunk @@ -70,8 +72,9 @@ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *in fclose(file); } - RCT2_GLOBAL(0x009AC31B, sint8) = -1; - RCT2_GLOBAL(0x009AC31C, sint16) = 3011; + log_error("invalid scenario, %s", path); + // RCT2_GLOBAL(0x009AC31B, sint8) = -1; + // RCT2_GLOBAL(0x009AC31C, sint16) = 3011; return 0; } @@ -205,6 +208,8 @@ int scenario_load_and_play_from_path(const char *path) if (!scenario_load(path)) return 0; + log_verbose("starting scenario, %s", path); + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING; viewport_init_all(); game_create_windows(); @@ -660,3 +665,62 @@ unsigned int scenario_rand() RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32) += ror32(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, uint32) ^ 0x1234567F, 7); return RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, uint32) = ror32(eax, 3); } + +/** + * Prepare rides, for the finish five rollercoasters objective. + * rct2: 0x006788F7 + */ +void scenario_prepare_rides_for_save() +{ + RCT2_CALLPROC_EBPSAFE(0x006788F7); +} + +/** + * + * rct2: 0x006726C7 + */ +int scenario_prepare_for_save() +{ + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + char buffer[256]; + + s6Info->entry.flags = 255; + + char *stex = RCT2_GLOBAL(0x009ADAE4, char*); + if (stex != (char*)0xFFFFFFFF) { + format_string(buffer, RCT2_GLOBAL(stex, uint16), NULL); + strncpy(s6Info->name, buffer, sizeof(s6Info->name)); + s6Info->entry = *((rct_object_entry*)0x00F4287C); + } + + if (s6Info->name[0] == 0) + format_string(s6Info->name, RCT2_GLOBAL(0x013573D4, rct_string_id), (void*)0x013573D8); + + s6Info->objective_type = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8); + s6Info->objective_arg_1 = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8); + s6Info->objective_arg_2 = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, uint8); + s6Info->objective_arg_3 = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint8); + + scenario_prepare_rides_for_save(); + + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_GUESTS_AND_RATING) + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_PARK_OPEN; + + return 1; +} + +/** + * + * rct2: 0x006754F5 + * @param flags bit 0: pack objects, 1: save as scenario + */ +int scenario_save(char *path, int flags) +{ + if (flags & 2) + log_verbose("saving scenario, %s", path); + else + log_verbose("saving game, %s", path); + + strcpy((char*)0x0141EF68, path); + return !(RCT2_CALLPROC_X(0x006754F5, flags, 0, 0, 0, 0, 0, 0) & 0x100); +} \ No newline at end of file diff --git a/src/scenario.h b/src/scenario.h index 221a673a22..b3b3a7ac54 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -408,5 +408,7 @@ int scenario_load_and_play(const rct_scenario_basic *scenario); int scenario_load_and_play_from_path(const char *path); void scenario_update(); unsigned int scenario_rand(); +int scenario_prepare_for_save(); +int scenario_save(char *path, int flags); #endif diff --git a/src/util/util.c b/src/util/util.c index 3ca951960c..8abdaca2ca 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -41,6 +41,19 @@ int mph_to_kmph(int mph) return (mph * 1648) / 1024; } +void path_set_extension(char *path, const char *extension) +{ + char *ch = path; + while (*ch != '.' && *ch != 0) { + ch++; + } + + if (extension[0] != '.') + *ch++ = '.'; + + strcpy(ch, extension); +} + long fsize(FILE *fp) { long originalPosition, size; diff --git a/src/util/util.h b/src/util/util.h index bef5f0adc3..82098918be 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -27,6 +27,7 @@ int squaredmetres_to_squaredfeet(int squaredMetres); int metres_to_feet(int metres); int mph_to_kmph(int mph); +void path_set_extension(char *path, const char *extension); long fsize(FILE *fp); int bitscanforward(int source); diff --git a/src/windows/editor_bottom_toolbar.c b/src/windows/editor_bottom_toolbar.c index 0f2ef811e0..5a357a8209 100644 --- a/src/windows/editor_bottom_toolbar.c +++ b/src/windows/editor_bottom_toolbar.c @@ -20,12 +20,18 @@ #include #include "../addresses.h" +#include "../audio/audio.h" +#include "../config.h" #include "../editor.h" +#include "../scenario.h" #include "../sprites.h" -#include "../localisation/string_ids.h" +#include "../localisation/localisation.h" #include "../interface/viewport.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../platform/osinterface.h" +#include "../title.h" +#include "../util/util.h" #include "error.h" enum WINDOW_EDITOR_TOP_TOOLBAR_WIDGET_IDX { @@ -250,11 +256,74 @@ void window_editor_bottom_toolbar_jump_forward_to_objective_selection() { } /** -* -* rct2: 0x0066f7c0 -*/ -void window_editor_bottom_toolbar_jump_forward_to_save_scenario() { - RCT2_CALLPROC_EBPSAFE(0x0066f7c0); + * + * rct2: 0x00675181 + */ +static int show_save_scenario_dialog(char *resultPath) +{ + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + + int result; + char title[256]; + char filename[MAX_PATH]; + char filterName[256]; + + + format_string(title, STR_SAVE_SCENARIO, NULL); + subsitute_path(filename, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), s6Info->name); + strcat(filename, ".SC6"); + format_string(filterName, STR_RCT2_SCENARIO_FILE, NULL); + + pause_sounds(); + result = osinterface_open_common_file_dialog(0, title, filename, "*.SC6", filterName); + unpause_sounds(); + + if (result) + strcpy(resultPath, filename); + return result; +} + +/** + * + * rct2: 0x0066F7C0 + */ +void window_editor_bottom_toolbar_jump_forward_to_save_scenario() +{ + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + int parkFlagsBackup, success; + char path[256]; + + if (!scenario_prepare_for_save()) { + window_error_open(STR_UNABLE_TO_SAVE_SCENARIO_FILE, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); + gfx_invalidate_screen(); + return; + } + + window_close_all(); + if (!show_save_scenario_dialog(path)) { + gfx_invalidate_screen(); + return; + } + + // + s6Info->var_000 = 255; + + // Ensure path has .SC6 extension + path_set_extension(path, ".SC6"); + + // Save the scenario + parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32); + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18; + success = scenario_save(path, gGeneral_config.save_plugin_data ? 3 : 2); + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup; + + if (success) { + // RCT2_CALLPROC_EBPSAFE(0x0066DC83); + title_load(); + } else { + window_error_open(STR_SCENARIO_SAVE_FAILED, -1); + s6Info->var_000 = 4; + } } /** diff --git a/src/windows/error.c b/src/windows/error.c index dddbfadcf2..531c40d00e 100644 --- a/src/windows/error.c +++ b/src/windows/error.c @@ -103,8 +103,7 @@ void window_error_open(rct_string_id title, rct_string_id message) dst += get_string_length(dst); } - printf(_window_error_text+1); - printf("\r\n"); + log_verbose("show error, %s", _window_error_text + 1); // Check if there is any text to display if (dst == _window_error_text + 1)