From 5874fb2b92cbb63ade5b5a90a48bc3a475b67ef2 Mon Sep 17 00:00:00 2001 From: Remnants of Forgotten Disney Date: Wed, 8 Nov 2023 15:06:23 -0600 Subject: [PATCH] Working in RS, as well as correct text --- include/debug_mode.h | 6 +- include/save_data_manager.h | 18 ++- include/script_builder.h | 31 +++-- source/main.cpp | 260 ++++++++++++++++++++--------------- source/pokedex.cpp | 2 +- source/pokemon_party.cpp | 5 +- source/random.cpp | 1 + source/save_data_manager.cpp | 15 +- source/script.cpp | 24 +++- source/script_array.cpp | 1 - source/script_builder.cpp | 118 ++++++++++------ 11 files changed, 291 insertions(+), 190 deletions(-) diff --git a/include/debug_mode.h b/include/debug_mode.h index 8ea3937..eb70bad 100644 --- a/include/debug_mode.h +++ b/include/debug_mode.h @@ -1,10 +1,10 @@ #ifndef DEBUG_MODE_H #define DEBUG_MODE_H -#define DEBUG_MODE false -#define IGNORE_LINK_CABLE false +#define DEBUG_MODE true +#define IGNORE_LINK_CABLE true #define DEBUG_GAME LEAFGREEN_ID #define DEBUG_VERS VERS_1_1 -// This is literally it. Yay. +#define DEBUG_LANG LANG_ENG #endif \ No newline at end of file diff --git a/include/save_data_manager.h b/include/save_data_manager.h index f8388c6..359dbcc 100644 --- a/include/save_data_manager.h +++ b/include/save_data_manager.h @@ -13,6 +13,13 @@ #define VERS_1_1 1 #define VERS_1_2 2 +#define LANG_JPN 'J' +#define LANG_ENG 'E' +#define LANG_FRE 'F' +#define LANG_GER 'D' +#define LANG_ITA 'I' +#define LANG_SPA 'S' + #define NUM_GAME_PAIRS 3 #define NUM_VERSIONS 3 @@ -24,19 +31,20 @@ // | Offset | Size | Contents // -------------------------- -#define TUTORIAL_FLAG 0x01 // | 0x1 | 1 | Has made it through the tutorial -#define CAUGHT_DATA 0x02 // | 0x2 | 31 | Flags for each Pokemon species -#define DEFAULT_LANGUAGE 0x21 // | 0x21 | 1 | Default international language +#define CAUGHT_DATA 0x00 // | 0x0 | 32 | Flags for each Pokemon species +#define TUTORIAL_FLAG 0x20 // | 0x1 | 1 | Has made it through the tutorial +#define DEFAULT_LANGUAGE 0x21 // | 0x22 | 1 | Default international language #define SAVE_DATA_SIZE 0x22 void load_gamecode(); -void load_save_data(); -void write_save_data(); +void load_custom_save_data(); +void write_custom_save_data(); bool is_caught(int dex_num); void set_caught(int dex_num); int get_def_lang(); void set_def_lang(int nLang); int get_gamecode(); int get_version(); +int get_language(); #endif diff --git a/include/script_builder.h b/include/script_builder.h index ac44c26..d70ff4b 100644 --- a/include/script_builder.h +++ b/include/script_builder.h @@ -28,6 +28,9 @@ #define TEXT_FULL 2 #define TEXT_RECEIVED 3 +#define TEXT_KANTO 0 +#define TEXT_HOENN 1 + #define NUM_ASM_OFFSET 8 #define ASM_OFFSET_PKMN_OFFSET 0 #define ASM_OFFSET_PKMN_STRUCT 1 @@ -87,7 +90,7 @@ class mystery_gift_script u8 value_buffer[9]; u32 jumppoint_location[NUM_JUMPS]; u32 jumppoint_destination[NUM_JUMPS]; - std::u16string_view textboxes[NUM_TEXTBOXES] = + std::u16string_view textboxes[2][NUM_TEXTBOXES] = // Ş = Wait for button and scroll text // ȼ = Wait for button and clear text // Ȇ = Escape character @@ -95,13 +98,20 @@ class mystery_gift_script // À = Player name // Ň = New line // ƞ = string terminator - { - //u": Hey ƲÀ!ȼPROFESSOR FENNEL told me that theseŇwere for you!ȼDon’t worry about making room…ŇI’ll send them to the PC!", - u": Hey ƲÀ!ȼPROFESSOR FENNEL told me that you’dŇbe swinging by!", - u": Thanks for helping out FENNEL!", - u": It looks like the PC is full…",//ȼCome back once you have more room!", - u"ƲÀ’S POKÉMON were sent to the PC!", - }; + {{ + // Kanto + u"BILL: Hey ƲÀ!ȼPROFESSOR FENNEL told me that you’dŇbe coming by for these POKÉMON!", + u"Thanks for helping out FENNEL!", + u"The PC is full…ȼGo make some more room!", + u"ȆÀÁƲÀ’S POKÉMON were sent to theŇPC!", + }, + { + // Hoenn + u"LANETTE: Hey ƲÀ!ȼPROFESSOR FENNEL told me that you’dŇbe coming by for these POKÉMON!", + u"Thanks for helping out FENNEL!", + u"The PC is full…ȼGo make some more room!", + u"ƲÀ’S POKÉMON were sent to the PC!", + }}; u32 textbox_location[NUM_TEXTBOXES]; u32 textbox_destination[NUM_TEXTBOXES]; u16 asm_offset_location[NUM_ASM_OFFSET]; @@ -115,7 +125,8 @@ public: mystery_gift_script(); void build_script(Pokemon incoming_party_array[]); u8 get_script_value_at(int index); - u16 calc_checksum(); + u32 calc_checksum32(); + u16 calc_crc16(); int get_offset_wondercard(); int get_offset_script(); int get_offset_flags(); @@ -162,7 +173,6 @@ private: void callstd(u8 function_index); void release(); void end(); - // ASM commands void push(u16 register_list); @@ -179,7 +189,6 @@ private: void and1(u8 rd, u8 rm); void ldr2(u8 rd, u8 rn, u8 rm); - // Custom scripting/ASM commands }; diff --git a/source/main.cpp b/source/main.cpp index 322c5d8..a10bd74 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -32,8 +32,9 @@ /*TODO: -------- -ACCURACY: +RESEARCH: - See if shiny Pokemon from gen 2 can be square shinies or if they're all normal +- Determine how tossing wonder cards works, and if we need to trash the script after it is finished LINK CABLE: - Figure out JP Gen 2 @@ -42,28 +43,50 @@ CONVERSION: - Add Korean conversion INJECTION: -- Add Pokemon to internal Pokedex -- Randomize base seed - Set flags for the number of Pokemon injected - Check what happens when the PC is full, but the last Pokemon doesn't exist (is zero) -- Set text color for FRLG for when a Pokemon is sent (what happens if you set it in RSE?) -- Check text overflow for the "recieved" text. What happens if the name is too long? - Maybe use the standard function for that? https://www.pokecommunity.com/showthread.php?t=201077 -- Figure out how to shrink the size of the mystery gift script. Especially with padding? idk, there's a lot of - multiple FFs and 00s - I think we can combine some of the ldr and add functions. +- Hall of Fame / Mystery Gift confirmation +- Korean GS Conversion +- Add in Rare Candies for new Pokemon +- Wonder Card +- Kill script? SAVE DATA: - Add warning - Add ability to erase - Add check for Hall of Fame +- Clear the empty data as part of the initalization +- Fix default language selection TESTING: - Test all the aspects of a Pokemon (Shiny, Pokerus, etc.) +- Make sure hall of fame data isn't corrupted +- Test all 14 different memory locations + +DEBUG: +- Remove number from "game didn't load" text + +GENERAL: +- Music +- Finalize Graphics +- Fade in and out + - Generalize graphics implementation? Load them only when needed and have one standard function? +- Add in sound effects for pressing buttons +- Credits (List all programs, people, and code- plus TPCI) + +FUTURE: +- Minigame +- Wii Channel +- Ditto Gift (Ignore Mew/Celebi?) +- MissingNo/Enigma Berry +- Text Translations +- Add support for other languages -------- */ Pokemon_Party party = Pokemon_Party(); +int delay_counter = 0; +bool skip = true; /* int test_main(void) @@ -94,122 +117,132 @@ int test_main(void) } } */ + +void initalization_script(void) +{ + // Initalizations + linkGPIO->reset(); + + REG_DISPCNT = DCNT_MODE0 | DCNT_BG0 | DCNT_BG1 | DCNT_BG2 | DCNT_BG3 | DCNT_OBJ | DCNT_OBJ_1D; + + irq_init(NULL); + irq_enable(II_VBLANK); + + flash_init(FLASH_SIZE_128KB); + rand_set_seed(0x1216); + init_text_engine(); + add_script_party_var(party); + + // Prepare dialouge + populate_dialouge(); + populate_script(); + + // Sound bank init + irq_init(NULL); + // irq_set(II_VBLANK, mmVBlank, 0); //Music + irq_enable(II_VBLANK); + // mmInitDefault((mm_addr)soundbank_bin, 8); //Music + // mmStart(MOD_FLATOUTLIES, MM_PLAY_LOOP); //Music + + // Graphics init + oam_init(obj_buffer, 128); + + // Load opening background first so it hides everything else + load_opening_background(); + load_background(); + load_textbox_background(); + load_testroid(); + load_professor(); + load_btn_t_l(); + load_btn_t_r(); + load_btn_p_l(); + load_btn_p_r(); + load_btn_c_l(); + load_btn_c_r(); + load_dex_l(); + load_dex_m(); + load_dex_r(); + load_btn_d_l(); + load_btn_d_r(); + load_btn_lang_eng(); + load_btn_lang_fre(); + load_btn_lang_ita(); + load_btn_lang_ger(); + load_btn_lang_spa(); + load_btn_lang_kor(); + load_lang_arrow(); + + main_menu_btn_init(Button(btn_t_l, btn_t_r, 128, 160), BTN_TRANSFER); + main_menu_btn_init(Button(btn_p_l, btn_p_r, 192, 224), BTN_POKEDEX); + main_menu_btn_init(Button(btn_c_l, btn_c_r, 256, 288), BTN_CREDITS); + main_menu_btn_init(Button(btn_d_l, btn_d_r, 416, 448), BTN_LANGUAGE); + + main_menu_btn_init(Button(btn_lang_eng, 480), BTN_ENG); + main_menu_btn_init(Button(btn_lang_fre, 512), BTN_FRE); + main_menu_btn_init(Button(btn_lang_ita, 544), BTN_ITA); + main_menu_btn_init(Button(btn_lang_ger, 576), BTN_GER); + main_menu_btn_init(Button(btn_lang_spa, 608), BTN_SPA); + main_menu_btn_init(Button(btn_lang_kor, 640), BTN_KOR); + main_menu_btn_init(Button(lang_arrow, 672), LANG_ARROW); + + pokedex_init(); // Why does this cause the music to stop playing? Also the loop doesn't work + + // main_menu_init(transfer_btn, pokedex_btn, credits_btn, language_btn); + + text_disable(); +}; + +void game_load_error(void) +{ + REG_BG0CNT = (REG_BG0CNT & ~BG_PRIO_MASK) | BG_PRIO(3); + REG_BG1CNT = (REG_BG1CNT & ~BG_PRIO_MASK) | BG_PRIO(2); + REG_BG2CNT = (REG_BG2CNT & ~BG_PRIO_MASK) | BG_PRIO(1); + REG_BG2VOFS = 0; + tte_set_pos(40, 24); + tte_set_margins(40, 24, 206, 104); + tte_write("The Pokemon save\nfile was not loaded successfully. Please\nrestart the console,\nload the Pokemon\ngame normally, and\nthen upload the\nprogram again."); + tte_write(std::to_string(get_gamecode() >> 8).c_str()); + key_poll(); + while (!key_hit(KEY_A)) + { + key_poll(); + VBlankIntrWait(); + } + tte_erase_screen(); + delay_counter = 0; + + while (delay_counter < 60) + { + delay_counter++; + VBlankIntrWait(); + } +} + int main(void) { - int delay_counter = 0; - bool skip = true; do { // Do not run on the first loop if (!skip) { - REG_BG0CNT = (REG_BG0CNT & ~BG_PRIO_MASK) | BG_PRIO(3); - REG_BG1CNT = (REG_BG1CNT & ~BG_PRIO_MASK) | BG_PRIO(2); - REG_BG2CNT = (REG_BG2CNT & ~BG_PRIO_MASK) | BG_PRIO(1); - REG_BG2VOFS = 0; - tte_set_pos(40, 24); - tte_set_margins(40, 24, 206, 104); - tte_write("The Pokemon save\nfile was not loaded successfully. Please\nrestart the console,\nload the Pokemon\ngame normally, and\nthen upload the\nprogram again."); - tte_write(std::to_string(get_gamecode() >> 8).c_str()); - key_poll(); - while (!key_hit(KEY_A)) - { - key_poll(); - VBlankIntrWait(); - } - tte_erase_screen(); - delay_counter = 0; - - while (delay_counter < 60) - { - delay_counter++; - VBlankIntrWait(); - } + game_load_error(); } skip = false; - // Initalizations - linkGPIO->reset(); - REG_DISPCNT = DCNT_MODE0 | DCNT_BG0 | DCNT_BG1 | DCNT_BG2 | DCNT_BG3 | DCNT_OBJ | DCNT_OBJ_1D; - - irq_init(NULL); - irq_enable(II_VBLANK); - - flash_init(FLASH_SIZE_128KB); - rand_set_seed(0x12162001); - init_text_engine(); - add_script_party_var(party); - - // Prepare dialouge - populate_dialouge(); - populate_script(); - - // Sound bank init - irq_init(NULL); - // irq_set(II_VBLANK, mmVBlank, 0); //Music - irq_enable(II_VBLANK); - // mmInitDefault((mm_addr)soundbank_bin, 8); //Music - // mmStart(MOD_FLATOUTLIES, MM_PLAY_LOOP); //Music - - // Graphics init - oam_init(obj_buffer, 128); - - // Load opening background first so it hides everything else - load_opening_background(); - load_background(); - load_textbox_background(); - load_testroid(); - load_professor(); - load_btn_t_l(); - load_btn_t_r(); - load_btn_p_l(); - load_btn_p_r(); - load_btn_c_l(); - load_btn_c_r(); - load_dex_l(); - load_dex_m(); - load_dex_r(); - load_btn_d_l(); - load_btn_d_r(); - load_btn_lang_eng(); - load_btn_lang_fre(); - load_btn_lang_ita(); - load_btn_lang_ger(); - load_btn_lang_spa(); - load_btn_lang_kor(); - load_lang_arrow(); - - main_menu_btn_init(Button(btn_t_l, btn_t_r, 128, 160), BTN_TRANSFER); - main_menu_btn_init(Button(btn_p_l, btn_p_r, 192, 224), BTN_POKEDEX); - main_menu_btn_init(Button(btn_c_l, btn_c_r, 256, 288), BTN_CREDITS); - main_menu_btn_init(Button(btn_d_l, btn_d_r, 416, 448), BTN_LANGUAGE); - - main_menu_btn_init(Button(btn_lang_eng, 480), BTN_ENG); - main_menu_btn_init(Button(btn_lang_fre, 512), BTN_FRE); - main_menu_btn_init(Button(btn_lang_ita, 544), BTN_ITA); - main_menu_btn_init(Button(btn_lang_ger, 576), BTN_GER); - main_menu_btn_init(Button(btn_lang_spa, 608), BTN_SPA); - main_menu_btn_init(Button(btn_lang_kor, 640), BTN_KOR); - main_menu_btn_init(Button(lang_arrow, 672), LANG_ARROW); - - pokedex_init(); // Why does this cause the music to stop playing? Also the loop doesn't work - - // main_menu_init(transfer_btn, pokedex_btn, credits_btn, language_btn); - - text_disable(); + initalization_script(); // Check if the game has been loaded correctly. load_gamecode(); - } while (!((get_gamecode() == RUBY_ID) || - (get_gamecode() == SAPPHIRE_ID) || - (get_gamecode() == FIRERED_ID) || - (get_gamecode() == LEAFGREEN_ID) || - (get_gamecode() == EMERALD_ID))); + } while ( + !(((get_gamecode() == RUBY_ID) || + (get_gamecode() == SAPPHIRE_ID) || + (get_gamecode() == FIRERED_ID) || + (get_gamecode() == LEAFGREEN_ID) || + (get_gamecode() == EMERALD_ID)) && + (get_language() == LANG_ENG))); // Prevents non-English games from loading - // Reinitalize the flash memory - // flash_init(FLASH_SIZE_128KB); // Initalize memory and save data after loading the game initalize_memory_locations(); - load_save_data(); + load_custom_save_data(); // Legal mumbo jumbo tte_set_pos(8, 0); @@ -226,6 +259,7 @@ int main(void) VBlankIntrWait(); } key_poll(); + // Gears of Progress tte_erase_rect(0, 0, 240, 160); REG_BG1VOFS = 0; @@ -246,10 +280,6 @@ int main(void) // Set up blend to fade to white/black - set_caught(3); - set_caught(15); - set_caught(5); - int curr_lang_btn_num = 3; int old_lang_btn_num = -1; set_arrow_point(curr_lang_btn_num); @@ -324,6 +354,8 @@ int main(void) key_poll(); rand_next_frame(); + tte_set_pos(0, 0); + // tte_write(std::to_string(get_rand_u32()).c_str()); background_frame(); text_next_frame(); oam_copy(oam_mem, obj_buffer, 35); diff --git a/source/pokedex.cpp b/source/pokedex.cpp index 1030938..853e6ed 100644 --- a/source/pokedex.cpp +++ b/source/pokedex.cpp @@ -77,7 +77,7 @@ int pokedex_loop() tte_set_pos(dex_x_cord + (1 * 8), (i * 8 * 3) + 16); tte_write(is_caught(dex_shift + i + 1) ? "^" : " "); tte_set_pos(dex_x_cord + (3 * 8), (i * 8 * 3) + 16); - tte_write(is_caught(dex_shift + i + 1) ? std::string(NAMES[dex_shift + i]).data() : "----------"); + tte_write(is_caught(dex_shift + i + 1) ? std::string(NAMES[dex_shift + i + 1]).data() : "----------"); tte_set_pos(dex_x_cord + (14 * 8), (i * 8 * 3) + 16); tte_write("000"); if(dex_shift + i + 1 < 10){ diff --git a/source/pokemon_party.cpp b/source/pokemon_party.cpp index 67435f3..ad00e6e 100644 --- a/source/pokemon_party.cpp +++ b/source/pokemon_party.cpp @@ -39,11 +39,11 @@ byte debug_party_data[GEN2_INT_SIZE + 4] = { // Japanese Gen 1 byte debug_party_data[GEN2_INT_SIZE + 4] = { // International Gen 2 0x8A, 0x91, 0x88, 0x92, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x06, - 0x8B, 0xC9, 0xA1, 0x97, 0xFB, 0x24, + 0x81, 0xC9, 0xA1, 0x97, 0xFB, 0x24, 0xFF, 0x25, 0xDA, - 0x8B, 0x00, 0x37, 0x21, 0x2C, 0x2B, 0x25, 0xDA, 0x00, 0x00, 0xA7, 0x00, 0x46, 0x00, 0x5C, 0x00, 0x44, 0x00, 0x28, 0x00, 0x46, 0xFA, 0xAA, 0x1F, 0x1E, 0xC0, 0x00, 0x45, 0xF2, 0x85, 0x81, 0x05, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x13, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0A, + 0x81, 0x00, 0x37, 0x21, 0x2C, 0x2B, 0x25, 0xDA, 0x00, 0x00, 0xA7, 0x00, 0x46, 0x00, 0x5C, 0x00, 0x44, 0x00, 0x28, 0x00, 0x46, 0xFA, 0xAA, 0x1F, 0x1E, 0xC0, 0x00, 0x45, 0xF2, 0x85, 0x81, 0x05, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x13, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0A, 0xC9, 0x00, 0x21, 0x27, 0xED, 0x00, 0x25, 0xDA, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x11, 0x23, 0x1E, 0x00, 0x00, 0x46, 0x00, 0x82, 0x82, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x07, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0xA1, 0x00, 0x21, 0x00, 0x00, 0x00, 0x25, 0xDA, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x8B, 0x23, 0x00, 0x00, 0x00, 0x46, 0x00, 0x83, 0x82, 0x03, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x97, 0x00, 0x21, 0x00, 0x00, 0x00, 0x25, 0xDA, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0x87, 0x21, 0x00, 0x00, 0x00, 0x46, 0x00, 0x82, 0x82, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0D, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, @@ -94,7 +94,6 @@ void Pokemon_Party::load_pokemon() for (int i = 0; i < 6; i++) { party[i].load_data(i, &party_data_array[0]); - rand_next_frame(); party[i].convert_to_gen_three(); } } diff --git a/source/random.cpp b/source/random.cpp index 2d1aa20..44d83c1 100644 --- a/source/random.cpp +++ b/source/random.cpp @@ -11,6 +11,7 @@ void rand_next_frame(){ } unsigned int get_rand_u32(){ + rand_next_frame(); return u32_rand; } diff --git a/source/save_data_manager.cpp b/source/save_data_manager.cpp index faa4eb4..dfacc69 100644 --- a/source/save_data_manager.cpp +++ b/source/save_data_manager.cpp @@ -8,6 +8,7 @@ int gamecode; int version; +int language; byte save_data_array[SAVE_DATA_SIZE]; void load_gamecode() @@ -16,17 +17,19 @@ void load_gamecode() { gamecode = DEBUG_GAME; version = DEBUG_VERS; + language = DEBUG_LANG; } else { gamecode = (*(vu8 *)(0x80000AC)) << 0x10 | (*(vu8 *)(0x80000AD)) << 0x08 | (*(vu8 *)(0x80000AE)) << 0x00; + language = (*(vu8 *)(0x80000AF)); version = (*(vu8 *)(0x80000BC)); } } -void load_save_data() +void load_custom_save_data() { flash_read(HALL_OF_FAME + 0x1000, &global_memory_buffer[0], 0x1000); for (int i = 0; i < SAVE_DATA_SIZE; i++) @@ -35,8 +38,9 @@ void load_save_data() } } -void write_save_data() +void write_custom_save_data() { + flash_read(HALL_OF_FAME + 0x1000, &global_memory_buffer[0], 0x1000); for (int i = 0; i < SAVE_DATA_SIZE; i++) { global_memory_buffer[HOF_SECTION + i] = save_data_array[i]; @@ -51,8 +55,7 @@ bool is_caught(int dex_num) void set_caught(int dex_num) { - load_save_data(); - save_data_array[CAUGHT_DATA + (dex_num / 8)] = global_memory_buffer[HOF_SECTION + CAUGHT_DATA + (dex_num / 8)] | (1 << (dex_num % 8)); + save_data_array[CAUGHT_DATA + (dex_num / 8)] = save_data_array[CAUGHT_DATA + (dex_num / 8)] | (1 << (dex_num % 8)); } int get_def_lang() @@ -89,4 +92,8 @@ int get_gamecode() int get_version() { return version; +} + +int get_language(){ + return language; } \ No newline at end of file diff --git a/source/script.cpp b/source/script.cpp index 530985a..440407a 100644 --- a/source/script.cpp +++ b/source/script.cpp @@ -7,13 +7,22 @@ static u32 wonder_card[0x14E] = { 0xFC, 0x85, 0x00, 0x00, 0xE8, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xCF, 0xCC, 0xC9, 0xCC, 0xBB, 0xCE, 0xC3, 0xBD, 0xC5, 0xBF, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xEC, 0xD7, 0xDC, 0xD5, 0xE2, 0xDB, 0xD9, 0x00, 0xBD, 0xD5, 0xE6, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0xE3, 0x00, 0xE8, 0xE3, 0x00, 0xE8, 0xDC, 0xD9, 0x00, 0xE7, 0xD9, 0xD7, 0xE3, 0xE2, 0xD8, 0x00, 0xDA, 0xE0, 0xE3, 0xE3, 0xE6, 0x00, 0xE3, 0xDA, 0x00, 0xE8, 0xDC, 0xD9, 0x00, 0xCA, 0xC9, 0xC5, 0x1B, 0xC7, 0xC9, 0xC8, 0x00, 0x00, 0x00, 0xBD, 0xBF, 0xC8, 0xCE, 0xBF, 0xCC, 0x00, 0xD5, 0xE2, 0xD8, 0x00, 0xE1, 0xD9, 0xD9, 0xE8, 0x00, 0xE8, 0xDC, 0xD9, 0x00, 0xD8, 0xD9, 0xE0, 0xDD, 0xEA, 0xD9, 0xE6, 0xED, 0x00, 0xE4, 0xD9, 0xE6, 0xE7, 0xE3, 0xE2, 0x00, 0xDD, 0xE2, 0x00, 0x00, 0xDB, 0xE6, 0xD9, 0xD9, 0xE2, 0xAD, 0x00, 0xCC, 0xD9, 0xD7, 0xD9, 0xDD, 0xEA, 0xD9, 0x00, 0xE8, 0xDC, 0xD9, 0x00, 0xBB, 0xCF, 0xCC, 0xC9, 0xCC, 0xBB, 0xCE, 0xC3, 0xBD, 0xC5, 0xBF, 0xCE, 0x00, 0xD5, 0xE2, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xDC, 0xD9, 0xE2, 0x00, 0xE7, 0xD5, 0xEA, 0xD9, 0x00, 0xE8, 0xDC, 0xD9, 0x00, 0xDB, 0xD5, 0xE1, 0xD9, 0xAB, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xE3, 0x00, 0xE2, 0xE3, 0xE8, 0x00, 0xE8, 0xE3, 0xE7, 0xE7, 0x00, 0xE8, 0xDC, 0xDD, 0xE7, 0x00, 0xBF, 0xEC, 0xD7, 0xDC, 0xD5, 0xE2, 0xDB, 0xD9, 0x00, 0xBD, 0xD5, 0xE6, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD9, 0xDA, 0xE3, 0xE6, 0xD9, 0x00, 0xE6, 0xD9, 0xD7, 0xD9, 0xDD, 0xEA, 0xDD, 0xE2, 0xDB, 0x00, 0xE8, 0xDC, 0xD9, 0x00, 0xBB, 0xCF, 0xCC, 0xC9, 0xCC, 0xBB, 0xCE, 0xC3, 0xBD, 0xC5, 0xBF, 0xCE, 0xAB, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00}; -// CRC16 checksum +// checksum void inject_mystery(Pokemon incoming_party_aray[]) { mystery_gift_script script; script.build_script(incoming_party_aray); - u16 checksum = script.calc_checksum(); + u32 checksum = 0; + switch (get_gamecode()) + { + case (RUBY_ID): + case (SAPPHIRE_ID): + checksum = script.calc_checksum32(); + break; + default: + checksum = script.calc_crc16(); + } flash_read(memory_section_array[4], &global_memory_buffer[0], 0x1000); for (int i = 0; i < 0x14E; i++) @@ -24,8 +33,8 @@ void inject_mystery(Pokemon incoming_party_aray[]) // Set checksum and padding global_memory_buffer[script.get_offset_script()] = checksum >> 0; global_memory_buffer[script.get_offset_script() + 1] = checksum >> 8; - global_memory_buffer[script.get_offset_script() + 2] = 0x00; - global_memory_buffer[script.get_offset_script() + 3] = 0x00; + global_memory_buffer[script.get_offset_script() + 2] = checksum >> 16; + global_memory_buffer[script.get_offset_script() + 3] = checksum >> 24; // Add in Mystery Script data for (int i = 0; i < MG_SCRIPT_SIZE; i++) @@ -41,4 +50,11 @@ void inject_mystery(Pokemon incoming_party_aray[]) global_memory_buffer[(script.get_offset_flags() + (FLAG_ID_START / 8)) % 0xF80] &= (~0b01000000 << (FLAG_ID_START % 8)); // Set "collected all" flag to 0 update_memory_buffer_checksum(); flash_write(memory_section_array[1 + ((script.get_offset_flags() + (FLAG_ID_START / 8)) / 0xF80)], &global_memory_buffer[0], 0x1000); + + // Update and save custom save data + for (int i = 0; i < 6; i++) + { + set_caught(incoming_party_aray[i].get_dex_number()); // Add the Pokemon to the dream dex + } + write_custom_save_data(); } \ No newline at end of file diff --git a/source/script_array.cpp b/source/script_array.cpp index a637eb1..922aae5 100644 --- a/source/script_array.cpp +++ b/source/script_array.cpp @@ -102,7 +102,6 @@ bool run_conditional(int index) case CMD_IMPORT_POKEMON: party_data.load_pokemon(); inject_mystery(party_data.get_full_pokemon_array()); - write_save_data(); return true; case CMD_BACK_TO_MENU: diff --git a/source/script_builder.cpp b/source/script_builder.cpp index 6b8efe4..c3b5444 100644 --- a/source/script_builder.cpp +++ b/source/script_builder.cpp @@ -39,13 +39,18 @@ int flag_all_collected = (FLAG_ID_START + 0x6); int loc_sendMonToPC; int loc_gSpecialVar_0x8000; -int loc_gSaveBlock1PTR; +int loc_gSaveBlock1; // Only used in R/S +int loc_gSaveBlock1PTR; // Only used in FR/LG/E int loc_setPokedexFlag; int offset_ramscript; // Source: https://github.com/pret/pokeemerald/blob/master/include/global.h#L1012 int offset_flags; // Flag offset as found within the SaveBlock1 struct in global.h int offset_wondercard; int offset_script; -std::string_view pc_maker; +int text_region; + +u8 map_bank; +u8 map_id; +u8 npc_id; mystery_gift_script::mystery_gift_script() { @@ -56,7 +61,10 @@ mystery_gift_script::mystery_gift_script() case (RUBY_ID): case (SAPPHIRE_ID): - pc_maker = "LANETTE"; + map_bank = 0; + map_id = 10; + npc_id = 1; + text_region = TEXT_HOENN; offset_wondercard = 0; offset_script = 0x0810; switch (get_version()) @@ -65,26 +73,26 @@ mystery_gift_script::mystery_gift_script() case (VERS_1_0): loc_sendMonToPC = 0x0803D998; loc_gSpecialVar_0x8000 = 0x0202E8C4; - loc_gSaveBlock1PTR = 0x02025734; - loc_setPokedexFlag = 0; - offset_ramscript = 0; - offset_flags = 0; + loc_gSaveBlock1 = 0x02025734; + loc_setPokedexFlag = 0x08090D90; + offset_ramscript = 0x3690; + offset_flags = 0x1220; break; case (VERS_1_1): - loc_sendMonToPC = 0; - loc_gSpecialVar_0x8000 = 0; - loc_gSaveBlock1PTR = 0; - loc_setPokedexFlag = 0; - offset_ramscript = 0; - offset_flags = 0; + loc_sendMonToPC = 0x0803D998; + loc_gSpecialVar_0x8000 = 0x0202E8C4; + loc_gSaveBlock1 = 0x02025734; + loc_setPokedexFlag = 0x08090DB0; + offset_ramscript = 0x3690; + offset_flags = 0x1220; break; case (VERS_1_2): - loc_sendMonToPC = 0; - loc_gSpecialVar_0x8000 = 0; - loc_gSaveBlock1PTR = 0; - loc_setPokedexFlag = 0; - offset_ramscript = 0; - offset_flags = 0; + loc_sendMonToPC = 0x0803D998; + loc_gSpecialVar_0x8000 = 0x0202E8C4; + loc_gSaveBlock1 = 0x02025734; + loc_setPokedexFlag = 0x08090DB0; + offset_ramscript = 0x3690; + offset_flags = 0x1220; break; } break; @@ -92,18 +100,21 @@ mystery_gift_script::mystery_gift_script() case (FIRERED_ID): case (LEAFGREEN_ID): - pc_maker = "BILL"; + map_bank = 30; + map_id = 0; + npc_id = 1; + text_region = TEXT_KANTO; offset_wondercard = 0x0460; offset_script = 0x079C; switch (get_version()) { case (VERS_1_0): - loc_sendMonToPC = 0; - loc_gSpecialVar_0x8000 = 0; - loc_gSaveBlock1PTR = 0; // Change this for RS - loc_setPokedexFlag = 0; - offset_ramscript = 0; - offset_flags = 0; + loc_sendMonToPC = 0x08040B90; + loc_gSpecialVar_0x8000 = 0x020370B8; + loc_gSaveBlock1PTR = 0x03005008; + loc_setPokedexFlag = 0x08088E74; + offset_ramscript = 0x361C; + offset_flags = 0x0EE0; break; case (VERS_1_1): loc_sendMonToPC = 0x08040BA4; @@ -118,7 +129,10 @@ mystery_gift_script::mystery_gift_script() case (EMERALD_ID): - pc_maker = "LANETTM"; + map_bank = 20; + map_id = 2; + npc_id = 1; + text_region = TEXT_HOENN; offset_wondercard = 0x056C; offset_script = 0x08A8; @@ -149,7 +163,7 @@ mystery_gift_script::mystery_gift_script() void mystery_gift_script::build_script(Pokemon incoming_party_array[]) { // Located at 0x?8A8 in the .sav - init_npc_location(0xFF, 0xFF, 0xFF); // Set the location of the NPC + init_npc_location(map_bank, map_id, npc_id); // Set the location of the NPC setvirtualaddress(0x08000000); // Set virtual address lock(); // Lock the player faceplayer(); // Have the NPC face the player @@ -161,10 +175,19 @@ void mystery_gift_script::build_script(Pokemon incoming_party_array[]) setvar(var_index, 0); // set the index to 0 setvar(var_callASM, rev_endian(0x0023)); // set the call_asm variable to 0x23: 0x23 = CALL ASM setvar(var_pkmn_offset, 0); // Set the Pokemon struct offset to 0 - copybyte(ptr_script_ptr_low, ptr_block_ptr_low); // Copy the first byte of the saveblock1ptr to a variable - copybyte(ptr_script_ptr_low + 1, ptr_block_ptr_low + 1); // Copy the second byte of the saveblock1ptr to a variable - copybyte(ptr_script_ptr_high, ptr_block_ptr_high); // Copy the third byte of the saveblock1ptr to a variable - copybyte(ptr_script_ptr_high + 1, ptr_block_ptr_high + 1); // Copy the fourth byte of the saveblock1ptr to a variable + switch (get_gamecode()) // Ruby and Sapphire don't shift their save blocks around, + { // so we can hardcode it + case (RUBY_ID): // + case (SAPPHIRE_ID): // FOR RUBY AND SAPPHIRE: + setvar(var_script_ptr_low, loc_gSaveBlock1 & 0xFFFF); // Copy the first two bytes of the saveblock1 location to a variable + setvar(var_script_ptr_high, loc_gSaveBlock1 >> 16); // Copy the second two bytes of the saveblock1 location to a variable + break; // + default: // FOR FIRERED, LEAFGREEN, AND EMERALD + copybyte(ptr_script_ptr_low, ptr_block_ptr_low); // Copy the first byte of the saveblock1ptr to a variable + copybyte(ptr_script_ptr_low + 1, ptr_block_ptr_low + 1); // Copy the second byte of the saveblock1ptr to a variable + copybyte(ptr_script_ptr_high, ptr_block_ptr_high); // Copy the third byte of the saveblock1ptr to a variable + copybyte(ptr_script_ptr_high + 1, ptr_block_ptr_high + 1); // Copy the fourth byte of the saveblock1ptr to a variable + } // addvar(var_script_ptr_low, offset_ramscript + 8 + READ_AS_THUMB); // add the offset for ramscript, plus 8. 8 is for the 8 bytes of Checksum, padding and NPC info addvar(var_script_ptr_low, get_ptr_offset(REL_PTR_ASM_START)); // Add the offset for the start of ASM setvar(var_call_return_1, rev_endian(0x0300)); // Set the vairable to 0x03. 0x03 = RETURN @@ -185,6 +208,8 @@ void mystery_gift_script::build_script(Pokemon incoming_party_array[]) call(ptr_callASM); // Call "PTR_DEX_START" again subvar(var_script_ptr_low, 28); // subtract from the CallASM offset so that it points to CALL_ASM again // THIS 28 IS STATIC AND MUST BE CHANGED IF ANY PART OF THE REL_PTR_ASM FUNCTION IS CHANGED. + // it would be smart to make this automatically modified, but this is so late into the process + // that it just simply isn't worth the effort at the moment /**/ set_jump_destination(JUMP_PKMN_COLLECTED); // Set the jump destination for if the Pokemon has already been collected addvar(var_pkmn_offset, POKEMON_SIZE); // Add the size of one Pokmeon to the Pokemon offset addvar(var_index, 1); // Add one to the index @@ -370,17 +395,9 @@ void mystery_gift_script::insert_textboxes() for (int i = 0; i < NUM_TEXTBOXES; i++) { textbox_destination[i] = curr_index - NPC_LOCATION_OFFSET; - if (i != TEXT_RECEIVED) + for (unsigned int parser = 0; parser < textboxes[text_region][i].length(); parser++) { - for (unsigned int parser = 0; parser < pc_maker.length(); parser++) - { - mg_script[curr_index] = get_gen_3_char((char16_t)(pc_maker.at(parser)), false); - curr_index++; - } - } - for (unsigned int parser = 0; parser < textboxes[i].length(); parser++) - { - mg_script[curr_index] = get_gen_3_char((char16_t)(textboxes[i].at(parser)), false); + mg_script[curr_index] = get_gen_3_char((char16_t)(textboxes[text_region][i].at(parser)), false); curr_index++; } mg_script[curr_index] = 0xFF; // End string @@ -388,7 +405,20 @@ void mystery_gift_script::insert_textboxes() } } -u16 mystery_gift_script::calc_checksum() // Implementation taken from PokeEmerald Decomp +u32 mystery_gift_script::calc_checksum32() +{ + u16 i; + u32 checksum = 0; + + for (i = 0; i < MG_SCRIPT_SIZE; i++) + { + checksum += mg_script[i]; + } + + return checksum; +} + +u16 mystery_gift_script::calc_crc16() // Implementation taken from PokeEmerald Decomp { u16 i, j; u16 crc = 0x1121; @@ -405,7 +435,7 @@ u16 mystery_gift_script::calc_checksum() // Implementation taken from PokeEmeral } } return ~crc; -} +}; void mystery_gift_script::add_asm(u16 command) {