diff --git a/include/debug_mode.h b/include/debug_mode.h index eb70bad..2b8b8ce 100644 --- a/include/debug_mode.h +++ b/include/debug_mode.h @@ -1,7 +1,7 @@ #ifndef DEBUG_MODE_H #define DEBUG_MODE_H -#define DEBUG_MODE true +#define DEBUG_MODE false #define IGNORE_LINK_CABLE true #define DEBUG_GAME LEAFGREEN_ID #define DEBUG_VERS VERS_1_1 diff --git a/include/flash_mem.h b/include/flash_mem.h index 8c970a1..069a901 100644 --- a/include/flash_mem.h +++ b/include/flash_mem.h @@ -2,6 +2,7 @@ #define MIRROR_H #include #include "pokemon.h" +#include "rom_data.h" #define MEM_CRAM 0x0E000000 // Cart RAM @@ -16,9 +17,10 @@ extern vu32 newest_save_offset; extern vu32 memory_section_array[]; extern char mem_name; extern u8 global_memory_buffer[0x1000]; +extern rom_data curr_rom; void initalize_memory_locations(); -bool insert_pokemon(Pokemon party_array[], int num); +//bool insert_pokemon(Pokemon party_array[], int num); void reverse_endian(u8 *data, size_t size); void update_memory_buffer_checksum(); bool get_flag(u16 flag_id); diff --git a/include/rom_data.h b/include/rom_data.h new file mode 100644 index 0000000..5fb3926 --- /dev/null +++ b/include/rom_data.h @@ -0,0 +1,46 @@ +#ifndef ROM_POINTERS_H +#define ROM_POINTERS_H + +#include + +#define RUBY_ID 0x415856 // AXV +#define SAPPHIRE_ID 0x415850 // AXP +#define FIRERED_ID 0x425052 // BPR +#define LEAFGREEN_ID 0x425047 // BPG +#define EMERALD_ID 0x425045 // BPE + +#define VERS_1_0 0 +#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' + +class rom_data +{ +public: + rom_data(); + bool load_rom(); + bool is_hoenn(); + bool is_ruby_sapphire(); + int loc_sendMonToPC; + int loc_gSpecialVar_0x8000; + int loc_gSaveBlock1; // Only used in R/S + int loc_gSaveBlock1PTR; // Only used in FR/LG/E + int loc_setPokedexFlag; + int offset_ramscript; // Ramscript offset as found within the SaveBlock1 struct in global.h + int offset_flags; // Flag offset as found within the SaveBlock1 struct in global.h + int offset_wondercard; + int offset_script; + int text_region; + + u8 map_bank; + u8 map_id; + u8 npc_id; +}; + +#endif \ No newline at end of file diff --git a/include/save_data_manager.h b/include/save_data_manager.h index 950bdc6..d3d1d2f 100644 --- a/include/save_data_manager.h +++ b/include/save_data_manager.h @@ -3,26 +3,6 @@ #include -#define RUBY_ID 0x415856 // AXV -#define SAPPHIRE_ID 0x415850 // AXP -#define FIRERED_ID 0x425052 // BPR -#define LEAFGREEN_ID 0x425047 // BPG -#define EMERALD_ID 0x425045 // BPE - -#define VERS_1_0 0 -#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 - #define HALL_OF_FAME 0x01C000 #define HOF_SECTION 2032 @@ -36,7 +16,6 @@ #define DEFAULT_LANGUAGE 0x21 // | 0x22 | 1 | Default international language #define SAVE_DATA_SIZE 0x22 -void load_gamecode(); void load_custom_save_data(); void write_custom_save_data(); bool is_caught(int dex_num); @@ -44,9 +23,6 @@ void set_caught(int dex_num); int get_def_lang(); void set_def_lang(int nLang); int get_def_lang_num(); -int get_gamecode(); -int get_version(); -int get_language(); bool get_tutorial_flag(); void set_tutorial_flag(bool value); void initalize_save_data(); diff --git a/include/script_array.h b/include/script_array.h index ceb7007..04d0d5c 100644 --- a/include/script_array.h +++ b/include/script_array.h @@ -3,6 +3,7 @@ #include "script_obj.h" #include "pokemon_party.h" +#include "rom_data.h" // Dialouge #define DIA_INDEX_OPEN 0 @@ -63,6 +64,7 @@ #define SCRIPT_SIZE COND_END extern script_obj script[]; +extern rom_data curr_rom; void populate_script(); void populate_dialogue(); diff --git a/source/flash_mem.cpp b/source/flash_mem.cpp index 9de7208..8cf0457 100644 --- a/source/flash_mem.cpp +++ b/source/flash_mem.cpp @@ -2,6 +2,7 @@ #include "flash_mem.h" #include "gba_flash.h" #include "pokemon.h" +#include "rom_data.h" #define pkmn_length 80 #define READ_SAVE_SECTIONS 5 diff --git a/source/main.cpp b/source/main.cpp index f235468..d5edcf0 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -29,6 +29,7 @@ #include "save_data_manager.h" #include "mystery_gift_injector.h" #include "mystery_gift_builder.h" +#include "rom_data.h" /*TODO: -------- @@ -65,7 +66,7 @@ FUTURE: Pokemon_Party party = Pokemon_Party(); int delay_counter = 0; bool skip = true; - +rom_data curr_rom; /* int test_main(void) { @@ -210,31 +211,20 @@ void first_load_message(void) int main(void) { - do - { // Do not run on the first loop - if (!skip) - { - game_load_error(); - } - skip = false; - + initalization_script(); + // Check if the game has been loaded correctly. + while (!curr_rom.load_rom()) + { + game_load_error(); 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)) && - (get_language() == LANG_ENG))); // Prevents non-English games from loading + } // Initalize memory and save data after loading the game initalize_memory_locations(); load_custom_save_data(); - if (get_tutorial_flag() == false){ + if (get_tutorial_flag() == false) + { first_load_message(); initalize_save_data(); } @@ -279,6 +269,8 @@ int main(void) int old_lang_btn_num = -1; set_arrow_point(curr_lang_btn_num); + curr_rom.load_rom(); + // MAIN LOOP while (1) { diff --git a/source/mystery_gift_builder.cpp b/source/mystery_gift_builder.cpp index 7867e7e..9afb958 100644 --- a/source/mystery_gift_builder.cpp +++ b/source/mystery_gift_builder.cpp @@ -2,7 +2,11 @@ #include "mystery_gift_builder.h" #include "pokemon_party.h" #include "pokemon_data.h" +#include "rom_data.h" +extern rom_data curr_rom; + +// These are static variables int var_callASM = (VAR_ID_START + 0x00); int var_script_ptr_low = (VAR_ID_START + 0x01); int var_script_ptr_high = (VAR_ID_START + 0x02); @@ -13,21 +17,7 @@ int var_box_return = (VAR_ID_START + 0x06); int var_dex_seen_caught = (VAR_ID_START + 0x07); int var_dex_num = (VAR_ID_START + 0x08); int var_index = (VAR_ID_START + 0x09); -int var_pkmn_offset = (VAR_ID_START + 0x0A); // FIX SWAPPING 0x8008 AND MAKE THE CODE COMMENTS CORRECT - -int ptr_callASM; -int ptr_script_ptr_low; -int ptr_script_ptr_high; -int ptr_call_return_1; -int ptr_call_check_flag; -int ptr_call_return_2; -int ptr_box_return; -int ptr_dex_seen_caught; -int ptr_index; -int ptr_pkmn_offset; - -int ptr_block_ptr_low; -int ptr_block_ptr_high; +int var_pkmn_offset = (VAR_ID_START + 0x0A); int flag_pkmn_1 = (FLAG_ID_START + 0x0); int flag_pkmn_2 = (FLAG_ID_START + 0x1); @@ -37,6 +27,8 @@ int flag_pkmn_5 = (FLAG_ID_START + 0x4); int flag_pkmn_6 = (FLAG_ID_START + 0x5); int flag_all_collected = (FLAG_ID_START + 0x6); +// These will all be set based on the ROM pointers +/* int loc_sendMonToPC; int loc_gSpecialVar_0x8000; int loc_gSaveBlock1; // Only used in R/S @@ -51,247 +43,173 @@ int text_region; u8 map_bank; u8 map_id; u8 npc_id; +*/ + +// These values will be defined once we recieve the ROM pointers +int ptr_callASM; +int ptr_script_ptr_low; +int ptr_script_ptr_high; +int ptr_call_return_1; +int ptr_call_check_flag; +int ptr_call_return_2; +int ptr_box_return; +int ptr_dex_seen_caught; +int ptr_index; +int ptr_pkmn_offset; + +int ptr_block_ptr_low; +int ptr_block_ptr_high; mystery_gift_script::mystery_gift_script() { curr_index = NPC_LOCATION_OFFSET; - switch (get_gamecode()) - { - case (RUBY_ID): - case (SAPPHIRE_ID): + ptr_callASM = (curr_rom.loc_gSpecialVar_0x8000 + 0x00); + ptr_script_ptr_low = (curr_rom.loc_gSpecialVar_0x8000 + 0x02); + ptr_script_ptr_high = (curr_rom.loc_gSpecialVar_0x8000 + 0x04); + ptr_call_return_1 = (curr_rom.loc_gSpecialVar_0x8000 + 0x06); + ptr_call_check_flag = (curr_rom.loc_gSpecialVar_0x8000 + 0x08); + ptr_call_return_2 = (curr_rom.loc_gSpecialVar_0x8000 + 0x0A); + ptr_box_return = (curr_rom.loc_gSpecialVar_0x8000 + 0x0C); + ptr_dex_seen_caught = (curr_rom.loc_gSpecialVar_0x8000 + 0x0E); + ptr_index = (curr_rom.loc_gSpecialVar_0x8000 + 0x12); + ptr_pkmn_offset = (curr_rom.loc_gSpecialVar_0x8000 + 0x14); - map_bank = 0; - map_id = 10; - npc_id = 1; - text_region = TEXT_HOENN; - offset_wondercard = 0; - offset_script = 0x0810; - switch (get_version()) - - { - case (VERS_1_0): - loc_sendMonToPC = 0x0803D998; - loc_gSpecialVar_0x8000 = 0x0202E8C4; - loc_gSaveBlock1 = 0x02025734; - loc_setPokedexFlag = 0x08090D90; - offset_ramscript = 0x3690; - offset_flags = 0x1220; - break; - case (VERS_1_1): - 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 = 0x0803D998; - loc_gSpecialVar_0x8000 = 0x0202E8C4; - loc_gSaveBlock1 = 0x02025734; - loc_setPokedexFlag = 0x08090DB0; - offset_ramscript = 0x3690; - offset_flags = 0x1220; - break; - } - break; - - case (FIRERED_ID): - case (LEAFGREEN_ID): - - 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 = 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; - loc_gSpecialVar_0x8000 = 0x020370B8; - loc_gSaveBlock1PTR = 0x03005008; - loc_setPokedexFlag = 0x08088E5C; - offset_ramscript = 0x361C; - offset_flags = 0x0EE0; - break; - } - break; - - case (EMERALD_ID): - - map_bank = 20; - map_id = 2; - npc_id = 1; - text_region = TEXT_HOENN; - offset_wondercard = 0x056C; - offset_script = 0x08A8; - - loc_sendMonToPC = 0x0806B490; - loc_gSpecialVar_0x8000 = 0x020375D8; - loc_gSaveBlock1PTR = 0x03005D8C; - loc_setPokedexFlag = 0x080C0664; - offset_ramscript = 0x3728; - offset_flags = 0x1270; - break; - } - - ptr_callASM = (loc_gSpecialVar_0x8000 + 0x00); - ptr_script_ptr_low = (loc_gSpecialVar_0x8000 + 0x02); - ptr_script_ptr_high = (loc_gSpecialVar_0x8000 + 0x04); - ptr_call_return_1 = (loc_gSpecialVar_0x8000 + 0x06); - ptr_call_check_flag = (loc_gSpecialVar_0x8000 + 0x08); - ptr_call_return_2 = (loc_gSpecialVar_0x8000 + 0x0A); - ptr_box_return = (loc_gSpecialVar_0x8000 + 0x0C); - ptr_dex_seen_caught = (loc_gSpecialVar_0x8000 + 0x0E); - ptr_index = (loc_gSpecialVar_0x8000 + 0x12); - ptr_pkmn_offset = (loc_gSpecialVar_0x8000 + 0x14); // EXPLAIN HERE TOO. Also like, we can and it?? - - ptr_block_ptr_low = (loc_gSaveBlock1PTR + 0x00); - ptr_block_ptr_high = (loc_gSaveBlock1PTR + 0x02); + ptr_block_ptr_low = (curr_rom.loc_gSaveBlock1PTR + 0x00); + ptr_block_ptr_high = (curr_rom.loc_gSaveBlock1PTR + 0x02); } void mystery_gift_script::build_script(Pokemon incoming_party_array[]) { // Located at 0x?8A8 in the .sav - 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 - checkflag(flag_all_collected); // Check if the "all collected" flag has been set - virtualgotoif(COND_FLAGTRUE, JUMP_ALL_COLLECTED); // If "all collected" is true, then jump to the "thank you" text - virtualmsgbox(TEXT_GREET); // Otherwise, greet the player - waitmsg(); // Wait for the message to finish - waitkeypress(); // Wait for the player to press A/B - 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 - 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 - setvar(var_call_check_flag, rev_endian(0x2B00)); // Set the variable to 0x2B. 0x2B = CHECK FLAG - addvar(var_call_check_flag, rev_endian(FLAG_ID_START)); // Add the starting flag ID to the check flag ASM variable - setvar(var_call_return_2, rev_endian(0x0003)); // Set the variable to 0x03. 0x03 = RETURN - /**/ set_jump_destination(JUMP_LOOP); // Set the jump destination for the JUMP_LOOP - call(ptr_call_check_flag); // Call the check flag ASM - virtualgotoif(COND_FLAGFALSE, JUMP_PKMN_COLLECTED); // If the "pokemon collected" flag is false, jump to the end of the loop - call(ptr_callASM); // Call SendMonToPC ASM - compare(var_box_return, 2); // Compare the resulting return to #2 - virtualgotoif(COND_EQUALS, JUMP_BOX_FULL); // If the return value was #2, jump to the box full message - addvar(var_script_ptr_low, 28); // add to the CallASM offset so that it points to PTR_DEX_START instead - // THIS 28 IS STATIC AND MUST BE CHANGED IF ANY PART OF THE REL_PTR_ASM FUNCTION IS CHANGED. - setvar(var_dex_seen_caught, 2); // set the seen caught variable to 2, so that the Pokemon is set to "seen" - call(ptr_callASM); // call "PTR_DEX_START" - addvar(var_dex_seen_caught, 1); // add 1 to the seen caught variable so that the Pokemon will be "Caught" - 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 - addvar(var_call_check_flag, rev_endian(1)); // Add one to the flag index - compare(var_index, 6); // Compare the index to 6 - virtualgotoif(COND_LESSTHAN, JUMP_LOOP); // if index is less than six, jump to the start of the loop - setflag(flag_all_collected); // Set the "all collected" flag - fanfare(0xA4); // Play the received fanfare - virtualmsgbox(TEXT_RECEIVED); // Display the recieved text - waitfanfare(); // Wait for the fanfare - waitmsg(); // Wait for the text to finish - waitkeypress(); // Wait for the player to press A/B - /**/ set_jump_destination(JUMP_ALL_COLLECTED); // Set the destination for if all the Pokemon have already been collected - virtualmsgbox(TEXT_THANK); // Display the thank test - waitmsg(); // Wait for the message - waitkeypress(); // Wait for the player to press A/B - release(); // Release the player - //end(); // End the script - killscript(); // Erase RAMscript - /**/ set_jump_destination(JUMP_BOX_FULL); // Set the destination for if the box is full - virtualmsgbox(TEXT_FULL); // Display the full box message - waitmsg(); // Wait for the message - waitkeypress(); // Wait for the player to presse A/B - release(); // Release the player - end(); // End the script - // - insert_textboxes(); // Insert textbox data - four_align(); // Align the code so that it is byte aligned - // - /**/ set_ptr_destination(REL_PTR_ASM_START); // Set the memory pointer location for ASM start - push(rlist_lr); // save the load register to the stack - ldr3(r3, asm_offset_distance(ASM_OFFSET_PKMN_OFFSET)); // set r3 to the pointer to the pokemon offset variable - ldr1(r3, r3, 0); // set r3 to the value in memory r3 points to - add5(r0, asm_offset_distance(ASM_OFFSET_PKMN_STRUCT)); // set r0 to a pointer 28 bytes ahead, which is the start of the Pokemon struct. - add3(r0, r0, r3); // add r3 to r0, giving it the correct offset for the current index - ldr3(r1, asm_offset_distance(ASM_OFFSET_SENDMON_PTR)); // set r1 to the location of "SendMonToPC" plus one, since it is thumb code - mov3(r2, r15); // move r15 (the program counter) to r2 - add2(r2, 5); // add 5 to r2 to compensate for the four following bytes, plus to tell the system to read as thumb code - mov3(r14, r2); // move r2 into r14 (the load register) - bx(r1); // jump to the pointer stored in r1 (SendMonToPC) - ldr3(r2, asm_offset_distance(ASM_OFFSET_BOX_SUC_PTR)); // load variable 0x8006's pointer into r2 - str1(r0, r2, 0); // put the value of r0 into the memory location pointed at by r2, plus 0 - pop(rlist_r0); // remove r0 from the stack and put it into r0 - bx(r0); // jump to r0 (return to where the function was called) - // - /*set_ptr_destination(REL_PTR_DEX_START);*/ // This stays commented out since the offset is not used. - push(rlist_lr); // save the load register to the stack - ldr3(r0, asm_offset_distance(ASM_OFFSET_INDEX)); // load the pointer to the index variable into r0 - ldr1(r0, r0, 0); // load the value at r0's pointer - mov1(r3, 0xFF); // load 0xFF into r3 - and1(r0, r3); // AND r0 and r3, which will give us just the least significant byte - add5(r1, asm_offset_distance(ASM_OFFSET_DEX_STRUCT)); // set r1 to the value stored X bytes ahead - add3(r0, r0, r1); // add r0 and r1, which is the current index and dex_struct respectivly - ldr1(r0, r0, 0); // load the value at the memory location stored in r0 - and1(r0, r3); // truncate to just the least significant byte, which is the current dex number - ldr3(r1, asm_offset_distance(ASM_OFFSET_DEX_SEEN_CAUGHT)); // load the dex_seen_caught variable's pointer into r1 - ldr1(r1, r1, 0); // load the value of memory pointed at by r1 - and1(r1, r3); // AND r1 and r3, which will keep only the least significant byte - ldr3(r2, asm_offset_distance(ASM_OFFSET_DEX_ASM_PTR_1)); // load the GetSetPokedexFlag function location into r2 - mov3(r3, r15); // move r15 (the program counter) to r3 - add2(r3, 5); // add 5 to r3 to compensate for the four following bytes, as well as to tell it to read as THUMB code - mov3(r14, r3); // move r3 into r14 (the load register) - // - bx(r2); // jump to the pointer stored in r2 (GetSetPokedexFlag) - pop(rlist_r0); // remove r0 from the stack and put it into r0 - bx(r0); // jump to r0 (return to where the function was called) - // - add_padding(); // add padding so that we are byte aligned again - set_asm_offset_destination(ASM_OFFSET_SENDMON_PTR); // set the SENDMON ptr offset - add_word(loc_sendMonToPC + READ_AS_THUMB); // the location of "SendMonToPC", plus one (so it is interpreted as thumb code) - set_asm_offset_destination(ASM_OFFSET_BOX_SUC_PTR); // set the BOX_SUCCESS ptr offset - add_word(ptr_box_return); // the location of variable "0x8006" (the return value) - set_asm_offset_destination(ASM_OFFSET_PKMN_OFFSET); // set the PKMN_OFFSET ptr offset - add_word(ptr_pkmn_offset); // the location of variable "0x8008" (the pokemon offset) - set_asm_offset_destination(ASM_OFFSET_DEX_ASM_PTR_1); // set the DEX_ASM_PTR offset - add_word(loc_setPokedexFlag + READ_AS_THUMB); // the location of GetSetPokedexFlag, plus one (so it is interpreted as thumb code) - set_asm_offset_destination(ASM_OFFSET_DEX_SEEN_CAUGHT); // set the DEX_SEEN_CAUGHT offset - add_word(ptr_dex_seen_caught); // the location of the DEX_SEEN_CAUGHT variable - set_asm_offset_destination(ASM_OFFSET_INDEX); // set the INDEX variable offset - add_word(ptr_index); // the location of the INDEX variable - // - set_asm_offset_destination(ASM_OFFSET_DEX_STRUCT); // set the DEX_STRUCT offset + init_npc_location(curr_rom.map_bank, curr_rom.map_id, curr_rom.npc_id); // Set the location of the NPC + setvirtualaddress(0x08000000); // Set virtual address + lock(); // Lock the player + faceplayer(); // Have the NPC face the player + checkflag(flag_all_collected); // Check if the "all collected" flag has been set + virtualgotoif(COND_FLAGTRUE, JUMP_ALL_COLLECTED); // If "all collected" is true, then jump to the "thank you" text + virtualmsgbox(TEXT_GREET); // Otherwise, greet the player + waitmsg(); // Wait for the message to finish + waitkeypress(); // Wait for the player to press A/B + 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 + if (curr_rom.is_ruby_sapphire()) // Ruby and Sapphire don't shift their save blocks around, so we can hardcode it + { // FOR RUBY AND SAPPHIRE: + setvar(var_script_ptr_low, curr_rom.loc_gSaveBlock1 & 0xFFFF); // Copy the first two bytes of the saveblock1 location to a variable + setvar(var_script_ptr_high, curr_rom.loc_gSaveBlock1 >> 16); // Copy the second two bytes of the saveblock1 location to a variable + } // + else // + { // 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, curr_rom.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 + setvar(var_call_check_flag, rev_endian(0x2B00)); // Set the variable to 0x2B. 0x2B = CHECK FLAG + addvar(var_call_check_flag, rev_endian(FLAG_ID_START)); // Add the starting flag ID to the check flag ASM variable + setvar(var_call_return_2, rev_endian(0x0003)); // Set the variable to 0x03. 0x03 = RETURN + /**/ set_jump_destination(JUMP_LOOP); // Set the jump destination for the JUMP_LOOP + call(ptr_call_check_flag); // Call the check flag ASM + virtualgotoif(COND_FLAGFALSE, JUMP_PKMN_COLLECTED); // If the "pokemon collected" flag is false, jump to the end of the loop + call(ptr_callASM); // Call SendMonToPC ASM + compare(var_box_return, 2); // Compare the resulting return to #2 + virtualgotoif(COND_EQUALS, JUMP_BOX_FULL); // If the return value was #2, jump to the box full message + addvar(var_script_ptr_low, 28); // add to the CallASM offset so that it points to PTR_DEX_START instead + // THIS 28 IS STATIC AND MUST BE CHANGED IF ANY PART OF THE REL_PTR_ASM FUNCTION IS CHANGED. + setvar(var_dex_seen_caught, 2); // set the seen caught variable to 2, so that the Pokemon is set to "seen" + call(ptr_callASM); // call "PTR_DEX_START" + addvar(var_dex_seen_caught, 1); // add 1 to the seen caught variable so that the Pokemon will be "Caught" + 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 + addvar(var_call_check_flag, rev_endian(1)); // Add one to the flag index + compare(var_index, 6); // Compare the index to 6 + virtualgotoif(COND_LESSTHAN, JUMP_LOOP); // if index is less than six, jump to the start of the loop + setflag(flag_all_collected); // Set the "all collected" flag + fanfare(0xA4); // Play the received fanfare + virtualmsgbox(TEXT_RECEIVED); // Display the recieved text + waitfanfare(); // Wait for the fanfare + waitmsg(); // Wait for the text to finish + waitkeypress(); // Wait for the player to press A/B + /**/ set_jump_destination(JUMP_ALL_COLLECTED); // Set the destination for if all the Pokemon have already been collected + virtualmsgbox(TEXT_THANK); // Display the thank test + waitmsg(); // Wait for the message + waitkeypress(); // Wait for the player to press A/B + release(); // Release the player + // end(); // End the script + killscript(); // Erase RAMscript + /**/ set_jump_destination(JUMP_BOX_FULL); // Set the destination for if the box is full + virtualmsgbox(TEXT_FULL); // Display the full box message + waitmsg(); // Wait for the message + waitkeypress(); // Wait for the player to presse A/B + release(); // Release the player + end(); // End the script + // + insert_textboxes(); // Insert textbox data + four_align(); // Align the code so that it is byte aligned + // + /**/ set_ptr_destination(REL_PTR_ASM_START); // Set the memory pointer location for ASM start + push(rlist_lr); // save the load register to the stack + ldr3(r3, asm_offset_distance(ASM_OFFSET_PKMN_OFFSET)); // set r3 to the pointer to the pokemon offset variable + ldr1(r3, r3, 0); // set r3 to the value in memory r3 points to + add5(r0, asm_offset_distance(ASM_OFFSET_PKMN_STRUCT)); // set r0 to a pointer 28 bytes ahead, which is the start of the Pokemon struct. + add3(r0, r0, r3); // add r3 to r0, giving it the correct offset for the current index + ldr3(r1, asm_offset_distance(ASM_OFFSET_SENDMON_PTR)); // set r1 to the location of "SendMonToPC" plus one, since it is thumb code + mov3(r2, r15); // move r15 (the program counter) to r2 + add2(r2, 5); // add 5 to r2 to compensate for the four following bytes, plus to tell the system to read as thumb code + mov3(r14, r2); // move r2 into r14 (the load register) + bx(r1); // jump to the pointer stored in r1 (SendMonToPC) + ldr3(r2, asm_offset_distance(ASM_OFFSET_BOX_SUC_PTR)); // load variable 0x8006's pointer into r2 + str1(r0, r2, 0); // put the value of r0 into the memory location pointed at by r2, plus 0 + pop(rlist_r0); // remove r0 from the stack and put it into r0 + bx(r0); // jump to r0 (return to where the function was called) + // + /*set_ptr_destination(REL_PTR_DEX_START);*/ // This stays commented out since the offset is not used. + push(rlist_lr); // save the load register to the stack + ldr3(r0, asm_offset_distance(ASM_OFFSET_INDEX)); // load the pointer to the index variable into r0 + ldr1(r0, r0, 0); // load the value at r0's pointer + mov1(r3, 0xFF); // load 0xFF into r3 + and1(r0, r3); // AND r0 and r3, which will give us just the least significant byte + add5(r1, asm_offset_distance(ASM_OFFSET_DEX_STRUCT)); // set r1 to the value stored X bytes ahead + add3(r0, r0, r1); // add r0 and r1, which is the current index and dex_struct respectivly + ldr1(r0, r0, 0); // load the value at the memory location stored in r0 + and1(r0, r3); // truncate to just the least significant byte, which is the current dex number + ldr3(r1, asm_offset_distance(ASM_OFFSET_DEX_SEEN_CAUGHT)); // load the dex_seen_caught variable's pointer into r1 + ldr1(r1, r1, 0); // load the value of memory pointed at by r1 + and1(r1, r3); // AND r1 and r3, which will keep only the least significant byte + ldr3(r2, asm_offset_distance(ASM_OFFSET_DEX_ASM_PTR_1)); // load the GetSetPokedexFlag function location into r2 + mov3(r3, r15); // move r15 (the program counter) to r3 + add2(r3, 5); // add 5 to r3 to compensate for the four following bytes, as well as to tell it to read as THUMB code + mov3(r14, r3); // move r3 into r14 (the load register) + // + bx(r2); // jump to the pointer stored in r2 (GetSetPokedexFlag) + pop(rlist_r0); // remove r0 from the stack and put it into r0 + bx(r0); // jump to r0 (return to where the function was called) + // + add_padding(); // add padding so that we are byte aligned again + set_asm_offset_destination(ASM_OFFSET_SENDMON_PTR); // set the SENDMON ptr offset + add_word(curr_rom.loc_sendMonToPC + READ_AS_THUMB); // the location of "SendMonToPC", plus one (so it is interpreted as thumb code) + set_asm_offset_destination(ASM_OFFSET_BOX_SUC_PTR); // set the BOX_SUCCESS ptr offset + add_word(ptr_box_return); // the location of variable "0x8006" (the return value) + set_asm_offset_destination(ASM_OFFSET_PKMN_OFFSET); // set the PKMN_OFFSET ptr offset + add_word(ptr_pkmn_offset); // the location of variable "0x8008" (the pokemon offset) + set_asm_offset_destination(ASM_OFFSET_DEX_ASM_PTR_1); // set the DEX_ASM_PTR offset + add_word(curr_rom.loc_setPokedexFlag + READ_AS_THUMB); // the location of GetSetPokedexFlag, plus one (so it is interpreted as thumb code) + set_asm_offset_destination(ASM_OFFSET_DEX_SEEN_CAUGHT); // set the DEX_SEEN_CAUGHT offset + add_word(ptr_dex_seen_caught); // the location of the DEX_SEEN_CAUGHT variable + set_asm_offset_destination(ASM_OFFSET_INDEX); // set the INDEX variable offset + add_word(ptr_index); // the location of the INDEX variable + // + set_asm_offset_destination(ASM_OFFSET_DEX_STRUCT); // set the DEX_STRUCT offset for (int i = 0; i < 6; i++) // Add in the dex numbers { @@ -350,17 +268,17 @@ void mystery_gift_script::add_command(int len) int mystery_gift_script::get_offset_wondercard() { - return offset_wondercard; + return curr_rom.offset_wondercard; } int mystery_gift_script::get_offset_script() { - return offset_script; + return curr_rom.offset_script; } int mystery_gift_script::get_offset_flags() { - return offset_flags; + return curr_rom.offset_flags; } void mystery_gift_script::fill_jumppoint_pointers() @@ -396,9 +314,9 @@ void mystery_gift_script::insert_textboxes() for (int i = 0; i < NUM_TEXTBOXES; i++) { textbox_destination[i] = curr_index - NPC_LOCATION_OFFSET; - for (unsigned int parser = 0; parser < textboxes[text_region][i].length(); parser++) + for (unsigned int parser = 0; parser < textboxes[curr_rom.text_region][i].length(); parser++) { - mg_script[curr_index] = get_gen_3_char((char16_t)(textboxes[text_region][i].at(parser)), false); + mg_script[curr_index] = get_gen_3_char((char16_t)(textboxes[curr_rom.text_region][i].at(parser)), false); curr_index++; } mg_script[curr_index] = 0xFF; // End string diff --git a/source/mystery_gift_injector.cpp b/source/mystery_gift_injector.cpp index 4eb0bc6..859bd54 100644 --- a/source/mystery_gift_injector.cpp +++ b/source/mystery_gift_injector.cpp @@ -14,13 +14,12 @@ void inject_mystery(Pokemon incoming_party_aray[]) mystery_gift_script script; script.build_script(incoming_party_aray); u32 checksum = 0; - switch (get_gamecode()) + if (curr_rom.is_ruby_sapphire()) { - case (RUBY_ID): - case (SAPPHIRE_ID): checksum = script.calc_checksum32(); - break; - default: + } + else + { checksum = script.calc_crc16(); } diff --git a/source/rom_data.cpp b/source/rom_data.cpp new file mode 100644 index 0000000..e59bd96 --- /dev/null +++ b/source/rom_data.cpp @@ -0,0 +1,132 @@ +#include "rom_data.h" +#include "mystery_gift_builder.h" +#include "pokemon_party.h" +#include "pokemon_data.h" + +int gamecode; +int version; +int language; + +rom_data::rom_data() {} +bool rom_data::load_rom() +{ + if (DEBUG_MODE) + { + 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)); + } + + // This section will need to be updated when more languages are added. It wil likely have to be a 3D array + if (language != LANG_ENG) + { + return false; + } + + switch (gamecode) + { + case (RUBY_ID): + case (SAPPHIRE_ID): + + map_bank = 0; + map_id = 10; + npc_id = 1; + text_region = TEXT_HOENN; + offset_wondercard = 0; + offset_script = 0x0810; + switch (version) + + { + case (VERS_1_0): + loc_sendMonToPC = 0x0803D998; + loc_gSpecialVar_0x8000 = 0x0202E8C4; + loc_gSaveBlock1 = 0x02025734; + loc_setPokedexFlag = 0x08090D90; + offset_ramscript = 0x3690; + offset_flags = 0x1220; + break; + case (VERS_1_1): + 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 = 0x0803D998; + loc_gSpecialVar_0x8000 = 0x0202E8C4; + loc_gSaveBlock1 = 0x02025734; + loc_setPokedexFlag = 0x08090DB0; + offset_ramscript = 0x3690; + offset_flags = 0x1220; + break; + } + return true; + + case (FIRERED_ID): + case (LEAFGREEN_ID): + + map_bank = 30; + map_id = 0; + npc_id = 1; + text_region = TEXT_KANTO; + offset_wondercard = 0x0460; + offset_script = 0x079C; + switch (version) + { + case (VERS_1_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; + loc_gSpecialVar_0x8000 = 0x020370B8; + loc_gSaveBlock1PTR = 0x03005008; + loc_setPokedexFlag = 0x08088E5C; + offset_ramscript = 0x361C; + offset_flags = 0x0EE0; + break; + } + return true; + + case (EMERALD_ID): + + map_bank = 20; + map_id = 2; + npc_id = 1; + text_region = TEXT_HOENN; + offset_wondercard = 0x056C; + offset_script = 0x08A8; + + loc_sendMonToPC = 0x0806B490; + loc_gSpecialVar_0x8000 = 0x020375D8; + loc_gSaveBlock1PTR = 0x03005D8C; + loc_setPokedexFlag = 0x080C0664; + offset_ramscript = 0x3728; + offset_flags = 0x1270; + return true; + } + return false; +} + +bool rom_data::is_hoenn() +{ + return (gamecode == RUBY_ID || gamecode == SAPPHIRE_ID || gamecode == EMERALD_ID); +} + +bool rom_data::is_ruby_sapphire(){ + return (gamecode == RUBY_ID || gamecode == SAPPHIRE_ID); +} diff --git a/source/save_data_manager.cpp b/source/save_data_manager.cpp index 9fd0ce9..e1d49b3 100644 --- a/source/save_data_manager.cpp +++ b/source/save_data_manager.cpp @@ -6,29 +6,8 @@ #include "main_menu.h" #include "pokemon_data.h" -int gamecode; -int version; -int language; byte save_data_array[SAVE_DATA_SIZE]; -void load_gamecode() -{ - if (DEBUG_MODE) - { - 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_custom_save_data() { flash_read(HALL_OF_FAME + 0x1000, &global_memory_buffer[0], 0x1000); @@ -89,21 +68,6 @@ void set_def_lang(int nLang) save_data_array[DEFAULT_LANGUAGE] = nLang; } -int get_gamecode() -{ - return gamecode; -} - -int get_version() -{ - return version; -} - -int get_language() -{ - return language; -} - void set_tutorial_flag(bool value) { save_data_array[TUTORIAL_FLAG] = value; diff --git a/source/script_array.cpp b/source/script_array.cpp index 433f8e0..59e3c26 100644 --- a/source/script_array.cpp +++ b/source/script_array.cpp @@ -121,26 +121,10 @@ bool run_conditional(int index) return true; case COND_IS_HOENN: - switch (get_gamecode()) - { - case (RUBY_ID): - case (SAPPHIRE_ID): - case (EMERALD_ID): - return true; - default: - return false; - } + return curr_rom.is_hoenn(); case COND_IS_FRLGE: - switch (get_gamecode()) - { - case (FIRERED_ID): - case (LEAFGREEN_ID): - case (EMERALD_ID): - return true; - default: - return false; - } + return !curr_rom.is_ruby_sapphire(); case CMD_START_LINK: party_data.start_link();