From 4459d127d00d7b5ca4785a13a4d3489e953cdeef Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Wed, 19 Nov 2014 21:46:32 +0000 Subject: [PATCH 1/5] Found cause of crash. Game will enter hybrid state when failed to load. --- src/game.c | 13 +++++++------ src/object_list.c | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/game.c b/src/game.c index 4a0a92fa08..cc188a1fb2 100644 --- a/src/game.c +++ b/src/game.c @@ -648,12 +648,7 @@ int game_load_save(const char *path) } } - if (!object_read_and_load_entries(file)){ - fclose(file); - RCT2_GLOBAL(0x009AC31B, uint8) = 255; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; - return 0; - }; + uint8 load_success = object_read_and_load_entries(file); // Read flags (16 bytes) sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); @@ -670,6 +665,12 @@ int game_load_save(const char *path) // Check expansion pack // RCT2_CALLPROC_EBPSAFE(0x006757E6); + if (!load_success){ + RCT2_CALLPROC_X(0x675827, 0, 0, 0, 0, 0, 0, 0); + RCT2_CALLPROC_X(0x66DC83, 0, 0, 0, 0, 0, 0, 0); + return; + } + // The rest is the same as in scenario load and play RCT2_CALLPROC_EBPSAFE(0x006A9FC0); map_update_tile_pointers(); diff --git a/src/object_list.c b/src/object_list.c index 4ddcf45712..6120d9e57b 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -202,7 +202,7 @@ int object_read_and_load_entries(FILE *file) // Failed to load the object //Destroy progress bar - memcpy((char*)0x13CE952, entries[i].name, 8); + memcpy((char*)0x13CE952, &entries[i], sizeof(rct_object_entry)); free(entries); object_unload_all(); RCT2_GLOBAL(0x14241BC, uint32) = 0; From 816f8661a53f0fc8b03896a4d8e4cd9f48bcd320 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Wed, 19 Nov 2014 22:05:42 +0000 Subject: [PATCH 2/5] Started adding sub_675827 --- src/game.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/game.c b/src/game.c index cc188a1fb2..41c2b96b63 100644 --- a/src/game.c +++ b/src/game.c @@ -607,6 +607,23 @@ static void load_landscape() } } +void sub_675827(){ + rct_object_entry* object = RCT2_ADDRESS(0x13CE952, rct_object_entry); + int ebx = (object->flags >> 4); + if (((object->flags >> 4) & 0xFF) == 0 + || ((object->flags >> 4) & 0xFF) == 8 + || RCT2_GLOBAL(0x9AB4C0, uint16) & (1 << (object->flags >> 4))){ + format_string(0x9BC677, 3323, 0); //Missing object data, ID: + + RCT2_CALLPROC_X(0x6AB344, 0, 0, 0, 0, 0, 0x9BC677, 0x13CE952); + RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; + RCT2_GLOBAL(0x9AC31C, uint16) = 3165; + return; + } + + //675846 +} + /** * * rct2: 0x00675E1B @@ -666,7 +683,8 @@ int game_load_save(const char *path) // RCT2_CALLPROC_EBPSAFE(0x006757E6); if (!load_success){ - RCT2_CALLPROC_X(0x675827, 0, 0, 0, 0, 0, 0, 0); + sub_675827(); + //RCT2_CALLPROC_X(0x675827, 0, 0, 0, 0, 0, 0, 0); RCT2_CALLPROC_X(0x66DC83, 0, 0, 0, 0, 0, 0, 0); return; } From e05d5f192225b29e69c03df330ef283258465ca8 Mon Sep 17 00:00:00 2001 From: Duncan Date: Thu, 20 Nov 2014 12:52:42 +0000 Subject: [PATCH 3/5] Add remaining part that caused load to enter hybrid sate. This should fix the remaining loading issues but it is untested at the moment. Note sub_675827 is not finished! --- src/game.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/game.c b/src/game.c index 41c2b96b63..cb9fbe3191 100644 --- a/src/game.c +++ b/src/game.c @@ -684,9 +684,14 @@ int game_load_save(const char *path) if (!load_success){ sub_675827(); - //RCT2_CALLPROC_X(0x675827, 0, 0, 0, 0, 0, 0, 0); - RCT2_CALLPROC_X(0x66DC83, 0, 0, 0, 0, 0, 0, 0); - return; + if (RCT2_GLOBAL(0x9DE518,uint32) & (1<<5)){ + RCT2_GLOBAL(0x14241BC, uint32) = 2; + //call 0x0040705E Sets cursor position and something else. Calls maybe wind func 8 probably pointless + RCT2_GLOBAL(0x14241BC, uint32) = 0; + RCT2_GLOBAL(0x9DE518, uint32) &= ~(1<<5); + } + title_load(); + return 0;// In the original this would call end_update but we get the same by returning 0 } // The rest is the same as in scenario load and play From 8e566e8598d61218a5fc0943dcbe199a39dd13ff Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Thu, 20 Nov 2014 18:40:10 +0000 Subject: [PATCH 4/5] Finished load related fail --- src/game.c | 52 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/game.c b/src/game.c index cb9fbe3191..0b205a8a02 100644 --- a/src/game.c +++ b/src/game.c @@ -532,16 +532,16 @@ static void game_load_or_quit() break; } - #ifdef _MSC_VER +#ifdef _MSC_VER __asm mov ebx, 0 - #else +#else __asm__ ( "mov ebx, 0 " ); - #endif +#endif } /** - * + * * rct2: 0x00674F40 */ static int open_landscape_file_dialog() @@ -558,7 +558,7 @@ static int open_landscape_file_dialog() } /** - * + * * rct2: 0x00674EB6 */ static int open_load_game_dialog() @@ -575,14 +575,15 @@ static int open_load_game_dialog() } /** - * + * * rct2: 0x0066DC0F */ static void load_landscape() { if (open_landscape_file_dialog() == 0) { gfx_invalidate_screen(); - } else { + } + else { // Set default filename char *esi = (char*)0x0141EF67; while (1) { @@ -600,28 +601,45 @@ static void load_landscape() if (1) { gfx_invalidate_screen(); rct2_endupdate(); - } else { + } + else { RCT2_GLOBAL(0x009DEA66, uint16) = 0; rct2_endupdate(); } } } -void sub_675827(){ +/* rct2: 0x675827 */ +void set_load_objects_fail_reason(){ rct_object_entry* object = RCT2_ADDRESS(0x13CE952, rct_object_entry); - int ebx = (object->flags >> 4); - if (((object->flags >> 4) & 0xFF) == 0 - || ((object->flags >> 4) & 0xFF) == 8 - || RCT2_GLOBAL(0x9AB4C0, uint16) & (1 << (object->flags >> 4))){ - format_string(0x9BC677, 3323, 0); //Missing object data, ID: + int expansion = (object->flags & 0xFF) >> 4; + if (expansion == 0 + || expansion == 8 + || RCT2_GLOBAL(0x9AB4C0, uint16) & (1 << expansion)){ - RCT2_CALLPROC_X(0x6AB344, 0, 0, 0, 0, 0, 0x9BC677, 0x13CE952); + char* string_buffer = RCT2_ADDRESS(0x9BC677, char); + + format_string(string_buffer, 3323, 0); //Missing object data, ID: + + RCT2_CALLPROC_X(0x6AB344, 0, 0, 0, 0, 0, (int)string_buffer, 0x13CE952); RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; RCT2_GLOBAL(0x9AC31C, uint16) = 3165; return; } - //675846 + char* exapansion_name = &RCT2_ADDRESS(RCT2_ADDRESS_EXPANSION_NAMES, char)[128 * expansion]; + if (*exapansion_name == '\0'){ + RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; + RCT2_GLOBAL(0x9AC31C, uint16) = 3325; + return; + } + + char* string_buffer = RCT2_ADDRESS(0x9BC677, char); + + format_string(string_buffer, 3324, 0); // Requires expansion pack + strcat(string_buffer, exapansion_name); + RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; + RCT2_GLOBAL(0x9AC31C, uint16) = 3165; } /** @@ -683,7 +701,7 @@ int game_load_save(const char *path) // RCT2_CALLPROC_EBPSAFE(0x006757E6); if (!load_success){ - sub_675827(); + set_load_objects_fail_reason(); if (RCT2_GLOBAL(0x9DE518,uint32) & (1<<5)){ RCT2_GLOBAL(0x14241BC, uint32) = 2; //call 0x0040705E Sets cursor position and something else. Calls maybe wind func 8 probably pointless From 7252667a25ffe9e13f7ee1d939cfa68eb61a25af Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Thu, 20 Nov 2014 19:02:27 +0000 Subject: [PATCH 5/5] Implemented the same changes to scenario load. Error messages now copied onto cmd prompt --- src/game.c | 36 ++---------------------------------- src/object.h | 1 + src/object_list.c | 34 ++++++++++++++++++++++++++++++++++ src/scenario.c | 10 ++++++++-- src/windows/error.c | 3 +++ 5 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/game.c b/src/game.c index 0b205a8a02..c688cad2a4 100644 --- a/src/game.c +++ b/src/game.c @@ -609,39 +609,6 @@ static void load_landscape() } } -/* rct2: 0x675827 */ -void set_load_objects_fail_reason(){ - rct_object_entry* object = RCT2_ADDRESS(0x13CE952, rct_object_entry); - int expansion = (object->flags & 0xFF) >> 4; - if (expansion == 0 - || expansion == 8 - || RCT2_GLOBAL(0x9AB4C0, uint16) & (1 << expansion)){ - - char* string_buffer = RCT2_ADDRESS(0x9BC677, char); - - format_string(string_buffer, 3323, 0); //Missing object data, ID: - - RCT2_CALLPROC_X(0x6AB344, 0, 0, 0, 0, 0, (int)string_buffer, 0x13CE952); - RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; - RCT2_GLOBAL(0x9AC31C, uint16) = 3165; - return; - } - - char* exapansion_name = &RCT2_ADDRESS(RCT2_ADDRESS_EXPANSION_NAMES, char)[128 * expansion]; - if (*exapansion_name == '\0'){ - RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; - RCT2_GLOBAL(0x9AC31C, uint16) = 3325; - return; - } - - char* string_buffer = RCT2_ADDRESS(0x9BC677, char); - - format_string(string_buffer, 3324, 0); // Requires expansion pack - strcat(string_buffer, exapansion_name); - RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; - RCT2_GLOBAL(0x9AC31C, uint16) = 3165; -} - /** * * rct2: 0x00675E1B @@ -709,7 +676,8 @@ int game_load_save(const char *path) RCT2_GLOBAL(0x9DE518, uint32) &= ~(1<<5); } title_load(); - return 0;// In the original this would call end_update but we get the same by returning 0 + rct2_endupdate(); + return 0;//This never gets called } // The rest is the same as in scenario load and play diff --git a/src/object.h b/src/object.h index a28f47a48f..1df0fd3f2a 100644 --- a/src/object.h +++ b/src/object.h @@ -48,6 +48,7 @@ extern int object_entry_group_counts[]; extern int object_entry_group_encoding[]; void object_list_load(); +void set_load_objects_fail_reason(); int object_read_and_load_entries(FILE *file); int object_load_packed(FILE *file); void object_unload_all(); diff --git a/src/object_list.c b/src/object_list.c index 6120d9e57b..953068bd6a 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -22,6 +22,7 @@ #include "addresses.h" #include "object.h" #include "util/sawyercoding.h" +#include "localisation/localisation.h" #define OBJECT_ENTRY_GROUP_COUNT 11 #define OBJECT_ENTRY_COUNT 721 @@ -169,6 +170,39 @@ static int check_object_entry(rct_object_entry *entry) return (0xFFFFFFFF & dwords[0] & dwords[1] & dwords[2] & dwords[3]) + 1 != 0; } +/* rct2: 0x675827 */ +void set_load_objects_fail_reason(){ + rct_object_entry* object = RCT2_ADDRESS(0x13CE952, rct_object_entry); + int expansion = (object->flags & 0xFF) >> 4; + if (expansion == 0 + || expansion == 8 + || RCT2_GLOBAL(0x9AB4C0, uint16) & (1 << expansion)){ + + char* string_buffer = RCT2_ADDRESS(0x9BC677, char); + + format_string(string_buffer, 3323, 0); //Missing object data, ID: + + RCT2_CALLPROC_X(0x6AB344, 0, 0, 0, 0, 0, (int)string_buffer, 0x13CE952); + RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; + RCT2_GLOBAL(0x9AC31C, uint16) = 3165; + return; + } + + char* exapansion_name = &RCT2_ADDRESS(RCT2_ADDRESS_EXPANSION_NAMES, char)[128 * expansion]; + if (*exapansion_name == '\0'){ + RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; + RCT2_GLOBAL(0x9AC31C, uint16) = 3325; + return; + } + + char* string_buffer = RCT2_ADDRESS(0x9BC677, char); + + format_string(string_buffer, 3324, 0); // Requires expansion pack + strcat(string_buffer, exapansion_name); + RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; + RCT2_GLOBAL(0x9AC31C, uint16) = 3165; +} + /** * * rct2: 0x006AA0C6 diff --git a/src/scenario.c b/src/scenario.c index 829f69c32e..745f52e0dd 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include +#include "title.h" #include "addresses.h" #include "game.h" #include "interface/viewport.h" @@ -110,7 +111,7 @@ int scenario_load(const char *path) object_list_load(); } - object_read_and_load_entries(file); + uint8 load_success = object_read_and_load_entries(file); // Read flags (16 bytes). Loads: // RCT2_ADDRESS_CURRENT_MONTH_YEAR @@ -147,7 +148,12 @@ int scenario_load(const char *path) sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE); fclose(file); - + if (!load_success){ + set_load_objects_fail_reason(); + title_load(); + rct2_endupdate(); + return 0;//This never gets called + } // Check expansion pack // RCT2_CALLPROC_EBPSAFE(0x006757E6); diff --git a/src/windows/error.c b/src/windows/error.c index 1fc74c8cd4..dddbfadcf2 100644 --- a/src/windows/error.c +++ b/src/windows/error.c @@ -103,6 +103,9 @@ 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"); + // Check if there is any text to display if (dst == _window_error_text + 1) return;