diff --git a/include/mystery_gift_builder.h b/include/mystery_gift_builder.h index 8061f5f..5bb074d 100644 --- a/include/mystery_gift_builder.h +++ b/include/mystery_gift_builder.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "pokemon_party.h" #include "debug_mode.h" #include "save_data_manager.h" @@ -99,14 +100,14 @@ class mystery_gift_script // Ň = New line // ƞ = string terminator {{ - // Kanto + // 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 + // 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!", @@ -114,7 +115,7 @@ class mystery_gift_script }}; u32 textbox_location[NUM_TEXTBOXES]; u32 textbox_destination[NUM_TEXTBOXES]; - u16 asm_offset_location[NUM_ASM_OFFSET]; +u16 asm_offset_location[NUM_ASM_OFFSET]; u16 asm_offset_destination[NUM_ASM_OFFSET]; u16 relative_offset_location[NUM_RELATIVE_PTR]; u16 relative_offset_destination[NUM_RELATIVE_PTR]; @@ -122,13 +123,12 @@ class mystery_gift_script public: mystery_gift_script(); - void build_script(Pokemon_Party incoming_box_data); + void build_script(Pokemon_Party &incoming_box_data); u8 get_script_value_at(int index); u32 calc_checksum32(); u16 calc_crc16(); bool validity_array[30]; - private: void add_command(int len); u16 rev_endian(u16 num); @@ -138,15 +138,15 @@ private: void fill_textbox_pointers(); void add_asm(u16 command); void fill_asm_pointers(); - void fill_relative_pointers(); +void fill_relative_pointers(); void set_jump_destination(u8 jumppoint_id); u8 get_ptr_offset(u8 jumppoint_id); void init_npc_location(u8 bank, u8 map, u8 npc); void add_word(u32 word); - void set_asm_offset_destination(u8 asm_offset_id); +void set_asm_offset_destination(u8 asm_offset_id); u8 asm_offset_distance(u8 asm_offset_id); void four_align(); - void set_ptr_destination(u8 relative_ptr_id); +void set_ptr_destination(u8 relative_ptr_id); void add_padding(); // Scripting commands @@ -191,4 +191,16 @@ private: // Custom scripting/ASM commands }; +class asm_var +{ +public: + asm_var(); + u32 set_value(u32 nValue, u32 currLoc); // Set the value of the variable + u32 add_script_location(u32 currLoc); // Add a location for the variable to be refrenced in the script + void set_pointer(u32 currLoc); // Add the pointer to where the variable is stored + void fill_script_pointers(u8 script_array[]); // goes through all the script locations and updates them to point to the value + u32 memory_location; + u32 value; + std::vector script_locations; +}; #endif diff --git a/include/mystery_gift_injector.h b/include/mystery_gift_injector.h index c02fb00..5d1d138 100644 --- a/include/mystery_gift_injector.h +++ b/include/mystery_gift_injector.h @@ -4,6 +4,6 @@ #include "pokemon_party.h" #include "mystery_gift_builder.h" -bool inject_mystery(Pokemon_Party incoming_box_data); +bool inject_mystery(Pokemon_Party &incoming_box_data); #endif \ No newline at end of file diff --git a/include/pokemon.h b/include/pokemon.h index 1e8c09f..98f556e 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -51,7 +51,7 @@ private: byte trainer_name[7]; byte pokerus; byte caught_data[2]; - byte level; + byte met_level; byte gen_3_pkmn[80]; byte unencrypted_data[49]; // Contains the 48 GAEM bytes, along with the modulo int byte pid[4] = {0b00000001, 0b10101010, 0b11111111, 0b10011001}; // Little Endian, reverse of Bulbapedia diff --git a/include/pokemon_party.h b/include/pokemon_party.h index a53230f..2ec18a3 100644 --- a/include/pokemon_party.h +++ b/include/pokemon_party.h @@ -4,6 +4,8 @@ #include #include "pokemon.h" +#define BOX_DATA_ARRAY_SIZE 0x462 + class Pokemon_Party { public: @@ -22,9 +24,9 @@ private: byte box_data_array[0x462]; int last_error; int num_pokemon; + bool has_new_pkmn; int game; char lang; - bool has_new_pkmn; }; #endif \ No newline at end of file diff --git a/source/gameboy_colour.cpp b/source/gameboy_colour.cpp index 8cb2c96..38f2105 100644 --- a/source/gameboy_colour.cpp +++ b/source/gameboy_colour.cpp @@ -199,6 +199,10 @@ int loop(byte *party_data) { VBlankIntrWait(); } + + if (counter > (60*10)){ + return COND_ERROR_TIMEOUT_ONE; + } } }; diff --git a/source/main.cpp b/source/main.cpp index 7289e43..f206d11 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -55,7 +55,7 @@ Post Beta TODO: -------- */ -Pokemon_Party party = Pokemon_Party(); +//Pokemon_Party party = Pokemon_Party(); int delay_counter = 0; bool skip = true; rom_data curr_rom; @@ -142,9 +142,6 @@ void initalization_script(void) REG_IME = 0; REG_IE = 0; - rand_set_seed(0x1216); - add_script_party_var(party); - // Sound bank init irq_init(NULL); // irq_set(II_VBLANK, mmVBlank, 0); //Music @@ -166,6 +163,8 @@ void initalization_script(void) // main_menu_init(transfer_btn, pokedex_btn, credits_btn, language_btn); text_disable(); + + rand_set_seed(0x1216); }; void game_load_error(void) diff --git a/source/mystery_gift_builder.cpp b/source/mystery_gift_builder.cpp index 078ecde..1d56a89 100644 --- a/source/mystery_gift_builder.cpp +++ b/source/mystery_gift_builder.cpp @@ -1,4 +1,5 @@ #include +#include #include "mystery_gift_builder.h" #include "pokemon_party.h" #include "pokemon_data.h" @@ -62,6 +63,10 @@ int ptr_block_ptr_high; mystery_gift_script::mystery_gift_script() { +#define NUM_RELATIVE_PTR 1 // THIS STAYS AS 1, THERE IS NO RELATIVE POINTER TO DEX AT THE MOMENT, IT IS A STATIC 28!!! +#define REL_PTR_ASM_START 0 +#define REL_PTR_DEX_START 1 + curr_index = NPC_LOCATION_OFFSET; ptr_callASM = (curr_rom.loc_gSpecialVar_0x8000 + 0x00); @@ -79,7 +84,7 @@ mystery_gift_script::mystery_gift_script() ptr_block_ptr_high = (curr_rom.loc_gSaveBlock1PTR + 0x02); } -void mystery_gift_script::build_script(Pokemon_Party incoming_box_data) +void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) { // Located at 0x?8A8 in the .sav init_npc_location(curr_rom.map_bank, curr_rom.map_id, curr_rom.npc_id); // Set the location of the NPC @@ -119,15 +124,15 @@ void mystery_gift_script::build_script(Pokemon_Party incoming_box_data) 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. + // 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 + // 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 @@ -152,10 +157,10 @@ void mystery_gift_script::build_script(Pokemon_Party incoming_box_data) 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 @@ -171,7 +176,7 @@ void mystery_gift_script::build_script(Pokemon_Party incoming_box_data) 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 @@ -189,11 +194,11 @@ void mystery_gift_script::build_script(Pokemon_Party incoming_box_data) 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) @@ -207,7 +212,7 @@ void mystery_gift_script::build_script(Pokemon_Party incoming_box_data) 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 < incoming_box_data.get_num_pkmn(); i++) // Add in the dex numbers @@ -215,7 +220,7 @@ void mystery_gift_script::build_script(Pokemon_Party incoming_box_data) mg_script[curr_index] = incoming_box_data.get_dex_num(i); curr_index++; } - curr_index += 2; // make the offset a multiple of 4 + four_align(); // make the offset a multiple of 4 set_asm_offset_destination(ASM_OFFSET_PKMN_STRUCT); // set the PKMN_STRUCT ptr offset @@ -234,7 +239,7 @@ void mystery_gift_script::build_script(Pokemon_Party incoming_box_data) fill_textbox_pointers(); fill_asm_pointers(); fill_relative_pointers(); - + if (curr_index > MG_SCRIPT_SIZE) { tte_erase_screen(); @@ -727,6 +732,7 @@ u8 mystery_gift_script::asm_offset_distance(u8 asm_offset_id) void mystery_gift_script::four_align() { + // while(curr_index % 4 != 0) for (int i = 0; i < curr_index % 4; i++) { mg_script[curr_index] = 0xFF; @@ -755,4 +761,32 @@ void mystery_gift_script::add_padding() { add_asm(0x0000); } +} + +asm_var::asm_var(){}; + +u32 asm_var::set_value(u32 nValue, u32 currLoc) +{ + value = nValue; + set_pointer(currLoc); + return value; +} + +void asm_var::set_pointer(u32 currLoc) +{ + memory_location = currLoc; +} + +u32 asm_var::add_script_location(u32 currLoc) +{ + script_locations.push_back(currLoc); + return 0x0000; +} + +void asm_var::fill_script_pointers(u8 script_array[]) +{ + for (int i = 0; i < script_locations.size(); i++) + { + script_array[script_locations.at(i)] = memory_location; + } } \ No newline at end of file diff --git a/source/mystery_gift_injector.cpp b/source/mystery_gift_injector.cpp index c0766c0..e646fb5 100644 --- a/source/mystery_gift_injector.cpp +++ b/source/mystery_gift_injector.cpp @@ -11,7 +11,7 @@ static u8 bill_wonder_card[0x14E] = { static u8 lanette_wonder_card[0x14E] = { 0x3F, 0x7C, 0x00, 0x00, 0xBA, 0xB4, 0xBE, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xCA, 0xCC, 0xC9, 0xC0, 0xBF, 0xCD, 0xCD, 0xC9, 0xCC, 0x00, 0xC0, 0xBF, 0xC8, 0xC8, 0xBF, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xE6, 0xD5, 0xE2, 0xE7, 0xDA, 0xD9, 0xE6, 0x00, 0xBD, 0xD9, 0xE6, 0xE8, 0xDD, 0xDA, 0xDD, 0xD7, 0xD5, 0xE8, 0xD9, 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, 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, 0x00, 0x00, 0xC2, 0xD9, 0xD5, 0xD8, 0x00, 0xE8, 0xE3, 0x00, 0xCC, 0xE3, 0xE9, 0xE8, 0xD9, 0x00, 0xA2, 0xA2, 0xA5, 0x00, 0xD5, 0xE2, 0xD8, 0x00, 0xD7, 0xDC, 0xD5, 0xE8, 0x00, 0xEB, 0xDD, 0xE8, 0xDC, 0x00, 0xC6, 0xBB, 0xC8, 0xBF, 0xCE, 0xCE, 0xBF, 0x00, 0xE8, 0xE3, 0x00, 0xDB, 0xD9, 0xE8, 0x00, 0xED, 0xE3, 0xE9, 0xE6, 0x00, 0xE8, 0xE6, 0xD5, 0xE2, 0xE7, 0xDA, 0xD9, 0xE6, 0xD9, 0xD8, 0x00, 0xCA, 0xC9, 0xC5, 0x1B, 0xC7, 0xC9, 0xC8, 0xAB, 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, 0x00, 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, 0xD6, 0xD9, 0xDA, 0xE3, 0xE6, 0xD9, 0x00, 0x00, 0x00, 0xE6, 0xD9, 0xD7, 0xD9, 0xDD, 0xEA, 0xDD, 0xE2, 0xDB, 0x00, 0xED, 0xE3, 0xE9, 0xE6, 0x00, 0xE8, 0xE6, 0xD5, 0xE2, 0xE7, 0xDA, 0xD9, 0xE6, 0xD9, 0xD8, 0x00, 0xCA, 0xC9, 0xC5, 0x1B, 0xC7, 0xC9, 0xC8, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // checksum -bool inject_mystery(Pokemon_Party incoming_box_data) +bool inject_mystery(Pokemon_Party &incoming_box_data) { mystery_gift_script script; script.build_script(incoming_box_data); @@ -25,6 +25,7 @@ bool inject_mystery(Pokemon_Party incoming_box_data) checksum = script.calc_crc16(); } + // Add in Wonder Card copy_save_to_ram(memory_section_array[4], &global_memory_buffer[0], 0x1000); if (curr_rom.is_hoenn()) { @@ -56,6 +57,21 @@ bool inject_mystery(Pokemon_Party incoming_box_data) erase_sector(memory_section_array[4]); copy_ram_to_save(&global_memory_buffer[0], memory_section_array[4], 0x1000); + // Add in Pokemon data + copy_save_to_ram(0x1C000, &global_memory_buffer[0], 0x1000); + int curr_index = 0; + for (int i = 0; i < incoming_box_data.get_num_pkmn(); i++) // Add in the Pokemon data + { + Pokemon curr_pkmn = incoming_box_data.get_converted_pkmn(i); + for (int curr_byte = 0; curr_byte < POKEMON_SIZE; curr_byte++) + { + global_memory_buffer[curr_index] = curr_pkmn.get_gen_3_data(curr_byte); + curr_index++; + } + script.validity_array[i] = curr_pkmn.get_validity(); + } + copy_ram_to_save(&global_memory_buffer[0], 0x1C000, 0x1000); + // Set flags copy_save_to_ram(memory_section_array[1 + ((curr_rom.offset_flags + (FLAG_ID_START / 8)) / 0xF80)], &global_memory_buffer[0], 0x1000); global_memory_buffer[(curr_rom.offset_flags + (FLAG_ID_START / 8)) % 0xF80] &= (~0b01111111 << (FLAG_ID_START % 8)); // Set "collected all" flag to 0 and reset the "to obtain" flags @@ -71,14 +87,7 @@ bool inject_mystery(Pokemon_Party incoming_box_data) erase_sector(memory_section_array[1 + ((curr_rom.offset_flags + (FLAG_ID_START / 8)) / 0xF80)]); copy_ram_to_save(&global_memory_buffer[0], memory_section_array[1 + ((curr_rom.offset_flags + (FLAG_ID_START / 8)) / 0xF80)], 0x1000); - // Update and save custom save data - for (int i = 0; i < incoming_box_data.get_num_pkmn(); i++) - { - if (script.validity_array[i]) - { - set_caught(incoming_box_data.get_dex_num(i)); // Add the Pokemon to the dream dex - } - } + // Save custom save data write_custom_save_data(); return true; } \ No newline at end of file diff --git a/source/pokemon.cpp b/source/pokemon.cpp index bcabbac..4f199f0 100644 --- a/source/pokemon.cpp +++ b/source/pokemon.cpp @@ -6,8 +6,12 @@ Pokemon::Pokemon(){}; +// TODO: Rewrite this with two different classes/structs that have arrays as input/output +// GBpkmn and GBApkmn + void Pokemon::load_data(int index, byte *party_data, int game, int lang) { + language = lang; if (lang == JPN_ID) { switch (game) @@ -18,10 +22,8 @@ void Pokemon::load_data(int index, byte *party_data, int game, int lang) case YELLOW_ID: gen = 1; pkmn_size = 44; - ot_and_party = 14; ot_size = 6; nickname_size = 6; - language = JPN_ID; box_size = 30; break; case GOLD_ID: @@ -29,10 +31,8 @@ void Pokemon::load_data(int index, byte *party_data, int game, int lang) case CRYSTAL_ID: gen = 2; pkmn_size = 48; - ot_and_party = 16; ot_size = 6; nickname_size = 6; - language = JPN_ID; box_size = 30; break; } @@ -46,11 +46,9 @@ void Pokemon::load_data(int index, byte *party_data, int game, int lang) case BLUE_ID: case YELLOW_ID: gen = 1; - pkmn_size = 44; - ot_and_party = 19; + pkmn_size = 33; ot_size = 11; nickname_size = 11; - language = INTERNATIONAL; box_size = 20; break; case GOLD_ID: @@ -58,577 +56,601 @@ void Pokemon::load_data(int index, byte *party_data, int game, int lang) case CRYSTAL_ID: gen = 2; pkmn_size = 48; - ot_and_party = 21; ot_size = 11; nickname_size = 11; - language = INTERNATIONAL; box_size = 20; break; } - int party_offset = ot_and_party + (index * pkmn_size); - int ot_offset = ot_and_party + (box_size * pkmn_size) + (index * ot_size); - int nickname_offset = ot_and_party + (box_size * pkmn_size) + (box_size * ot_size) + (index * nickname_size); + int party_species_offset = + 1 + // the num pkmn byte + (1 * index); // the pkmn index we're looking for + + int box_struct_offset = + 1 + // the num of pkmn byte + (1 * box_size) + 1 + // list of pkmn in box and terminator + (pkmn_size * index); // the pokemon we're looking for + + int ot_offset = + 1 + // the num of pkmn byte + (1 * box_size) + 1 + // list of pkmn in box and terminator + (pkmn_size * box_size) + // the pokemon structs + (ot_size * index); // the ot we're looking for + + int nickname_offset = + 1 + // the num of pkmn byte + (1 * box_size) + 1 + // list of pkmn in box and terminator + (pkmn_size * box_size) + // the pokemon structs + (ot_size * box_size) + // the ots + (nickname_size * index); // the nickname we're looking for switch (gen) { case 1: - species_index_party = gen_1_index_array[party_data[ot_size + 1 + index]]; - species_index_struct = gen_1_index_array[party_data[party_offset + 0x00]]; - copy_from_to(&party_data[party_offset + 0x08], &moves[0], 4, false); - copy_from_to(&party_data[party_offset + 0x0C], &trainer_id[0], 2, false); - copy_from_to(&party_data[party_offset + 0x0E], &exp[0], 3, true); + //tte_write(std::to_string(party_data[1121]).c_str()); + //while (true){}; + species_index_party = party_data[party_species_offset]; + species_index_struct = party_data[box_struct_offset + 0x00]; + met_level = party_data[box_struct_offset + 0x03]; + copy_from_to(&party_data[box_struct_offset + 0x08], &moves[0], 4, false); + copy_from_to(&party_data[box_struct_offset + 0x0C], &trainer_id[0], 2, false); + copy_from_to(&party_data[box_struct_offset + 0x0E], &exp[0], 3, true); + copy_from_to(&party_data[box_struct_offset + 0x1B], &dvs[0], 2, false); + copy_from_to(&party_data[box_struct_offset + 0x1D], &pp_values[0], 4, false); copy_from_to(&party_data[nickname_offset], &nickname[0], 10, false); - copy_from_to(&party_data[ot_offset + 0x00], &trainer_name[0], 7, false); - copy_from_to(&party_data[party_offset + 0x1B], &dvs[0], 2, false); - copy_from_to(&party_data[party_offset + 0x1D], &pp_values[0], 4, false); + copy_from_to(&party_data[ot_offset], &trainer_name[0], 7, false); + // Data not in gen 1 pokerus = 0x00; caught_data[0] = 0x00; caught_data[1] = 0x00; - level = party_data[party_offset + 0x21]; + break; case 2: - species_index_party = party_data[ot_size + 1 + index]; - species_index_struct = party_data[party_offset + 0x00]; - copy_from_to(&party_data[party_offset + 0x02], &moves[0], 4, false); - copy_from_to(&party_data[party_offset + 0x06], &trainer_id[0], 2, false); - copy_from_to(&party_data[party_offset + 0x08], &exp[0], 3, true); + species_index_party = party_data[party_species_offset]; + species_index_struct = party_data[box_struct_offset + 0x00]; + copy_from_to(&party_data[box_struct_offset + 0x02], &moves[0], 4, false); + copy_from_to(&party_data[box_struct_offset + 0x06], &trainer_id[0], 2, false); + copy_from_to(&party_data[box_struct_offset + 0x08], &exp[0], 3, true); + copy_from_to(&party_data[box_struct_offset + 0x15], &dvs[0], 2, false); + copy_from_to(&party_data[box_struct_offset + 0x17], &pp_values[0], 4, false); + pokerus = party_data[box_struct_offset + 0x1C]; + copy_from_to(&party_data[box_struct_offset + 0x1D], &caught_data[0], 2, false); + met_level = party_data[box_struct_offset + 0x1F]; copy_from_to(&party_data[nickname_offset], &nickname[0], 10, false); copy_from_to(&party_data[ot_offset + 0x00], &trainer_name[0], 7, false); - copy_from_to(&party_data[party_offset + 0x15], &dvs[0], 2, false); - copy_from_to(&party_data[party_offset + 0x17], &pp_values[0], 4, false); - pokerus = party_data[party_offset + 0x1C]; - copy_from_to(&party_data[party_offset + 0x1D], &caught_data[0], 2, false); - level = party_data[party_offset + 0x1F]; break; } } } - void Pokemon::convert_to_gen_three() +void Pokemon::convert_to_gen_three() +{ + // Convert the species indexes + if (gen == 1) + { + species_index_party = gen_1_index_array[species_index_party]; + species_index_struct = gen_1_index_array[species_index_struct]; + } + + if (species_index_struct > 251 || // Checks if the Pokemon is beyond Celebi + species_index_struct == 0 || // Checks that the Pokemon isn't a blank party space + species_index_struct != species_index_party) // Checks that the Pokemon isn't a hybrid or an egg + { + // while(true){}; + // is_valid = false; + // return; + } + is_valid = true; + // Generate PID + u32 n_pid = generate_pid(species_index_struct, *(vu32 *)exp % 25, &dvs[0]); + for (int i = 0; i < 4; i++) + { + pid[i] = (n_pid >> (i * 8)) & 0xFF; + } + + // Make sure Level is not over 100 based on EXP + if (*(vu32 *)exp > get_max_exp(species_index_struct)) + { + *(vu32 *)exp = get_max_exp(species_index_struct); + } + + // Separate the PP Up values from the Move PP values + for (int i = 0; i < 4; i++) + { + pure_pp_values[i] = (pp_values[i] & 0b00111111); // Take only the bottom six bits + pp_bonus[i] = (pp_values[i] >> 6); // Take only the top two bits + } + + // Check that the moves are valid + if (species_index_struct != 0xEB) // Ignore Smeargle due to Sketch { - if (species_index_struct > 251 || // Checks if the Pokemon is beyond Celebi - species_index_struct == 0 || // Checks that the Pokemon isn't a blank party space - species_index_struct != species_index_party) // Checks that the Pokemon isn't a hybrid or an egg - { - is_valid = false; - return; - } - is_valid = true; - // Generate PID - u32 n_pid = generate_pid(species_index_struct, *(vu32 *)exp % 25, &dvs[0]); for (int i = 0; i < 4; i++) { - pid[i] = (n_pid >> (i * 8)) & 0xFF; - } - - // Make sure Level is not over 100 based on EXP - if (*(vu32 *)exp > get_max_exp(species_index_struct)) - { - *(vu32 *)exp = get_max_exp(species_index_struct); - } - - // Separate the PP Up values from the Move PP values - for (int i = 0; i < 4; i++) - { - pure_pp_values[i] = (pp_values[i] & 0b00111111); // Take only the bottom six bits - pp_bonus[i] = (pp_values[i] >> 6); // Take only the top two bits - } - - // Check that the moves are valid - if (species_index_struct != 0xEB) // Ignore Smeargle due to Sketch - { - for (int i = 0; i < 4; i++) + if ((!can_learn_move(species_index_struct, moves[i])) && (moves[i] != 0)) { - if ((!can_learn_move(species_index_struct, moves[i])) && (moves[i] != 0)) - { - moves[i] = 0; // Remove the move - pp_bonus[i] = 0; // Remove the PP bonus - } + moves[i] = 0; // Remove the move + pp_bonus[i] = 0; // Remove the PP bonus + } + } + } + + // Make sure it has at least one move + if (moves[0] + moves[1] + moves[2] + moves[3] == 0) + { + moves[0] = get_earliest_move(species_index_struct); + } + + // Bubble valid moves to the top + int i, j; + bool swapped; + for (i = 0; i < 3; i++) + { + swapped = false; + for (j = 0; j < 3 - i; j++) + { + if ((moves[j] < moves[j + 1]) && moves[j] == 0) + { + // Move the move *and* PP bonus up if there is a blank space + moves[j] = moves[j + 1]; + pp_bonus[j] = pp_bonus[j + 1]; + moves[j + 1] = 0; + pp_bonus[j + 1] = 0; + swapped = true; } } - // Make sure it has at least one move - if (moves[0] + moves[1] + moves[2] + moves[3] == 0) + // If no two elements were swapped + // by inner loop, then break + if (swapped == false) + break; + } + + // Restore the PP values + for (int i = 0; i < 4; i++) + { + pure_pp_values[i] = POWER_POINTS[moves[i]] + ((POWER_POINTS[moves[i]] / 5) * pp_bonus[i]); + } + + // Convert and set IVs + int hp_iv = 0; + for (int i = 0; i < 4; i++) + { + ivs[i + 1] = (dvs[i / 2] >> (((i + 1) % 2) * 4)) & 0b1111; + hp_iv |= ((ivs[i + 1] & 0x1) << i); + }; + ivs[0] = hp_iv; + ivs[5] = ivs[4]; + + for (int i = 0; i < 6; i++) + { + ivs[i] = (ivs[i] * 2) + 1; + iv_egg_ability |= ((ivs[i] & 0b11111) << (i * 5)); + } + + // Determine and set Ability + iv_egg_ability |= ((pid[0] & 0x1) ? get_num_abilities(species_index_struct) : 0) << 31; + + // Origin info + origin_info |= ((caught_data[1] & 0b10000000) << 8); // OT gender - We would shift left 15 bits, but the bit is already shifted over 7 + origin_info |= (4 << 11); // Ball + origin_info |= (((gen == 1) ? 4 : 7) << 7); // Game + origin_info |= met_level; // Level met + + // Ribbons and Obedience + // ribbons[2] |= 0b00000100; // Artist Ribbon + ribbons[3] |= 0b10000000; // Fateful Encounter flag + // Personality Value + copy_from_to(&pid[0], &gen_3_pkmn[0], 4, false); + // Trainer ID + copy_from_to(&trainer_id[0], &gen_3_pkmn[4], 2, true); + + // Check if the Pokemon is shiny + if ( // Is shiny + (dvs[1] == 0b10101010) && // Checks if the Speed and Special DVs equal 10 + ((dvs[0] & 0xF) == 0b1010) && // Checks if the Defense DVs equal 10 + (((dvs[0] & 0b11000000) >> 6) | (((dvs[0] & 0b00110000) >> 2) > 7))) // Reorganizes the Attack DV bits so that they will be >7 if the Pokemon is shiny + { + secret_id[0] = trainer_id[0] ^ pid[0] ^ pid[2] ^ 0xFF; + secret_id[1] = trainer_id[1] ^ pid[1] ^ pid[3] ^ 0xFF; + // Randomly shift by 16 (maybe) + } + else // Not shiny, make sure it isn't + { + if (((trainer_id[0] ^ secret_id[0] ^ pid[0] ^ pid[2]) == 0) && + ((trainer_id[1] ^ secret_id[1] ^ pid[1] ^ pid[3]) > 7)) { - moves[0] = get_earliest_move(species_index_struct); + secret_id[0] = 0xFF; + secret_id[1] = 0xFF; } + } + copy_from_to(&secret_id[0], &gen_3_pkmn[6], 2, false); // Set SID - // Bubble valid moves to the top - int i, j; - bool swapped; - for (i = 0; i < 3; i++) - { - swapped = false; - for (j = 0; j < 3 - i; j++) - { - if ((moves[j] < moves[j + 1]) && moves[j] == 0) - { - // Move the move *and* PP bonus up if there is a blank space - moves[j] = moves[j + 1]; - pp_bonus[j] = pp_bonus[j + 1]; - moves[j + 1] = 0; - pp_bonus[j + 1] = 0; - swapped = true; - } - } - - // If no two elements were swapped - // by inner loop, then break - if (swapped == false) - break; - } - - // Restore the PP values - for (int i = 0; i < 4; i++) - { - pure_pp_values[i] = POWER_POINTS[moves[i]] + ((POWER_POINTS[moves[i]] / 5) * pp_bonus[i]); - } - - // Convert and set IVs - int hp_iv = 0; - for (int i = 0; i < 4; i++) - { - ivs[i + 1] = (dvs[i / 2] >> (((i + 1) % 2) * 4)) & 0b1111; - hp_iv |= ((ivs[i + 1] & 0x1) << i); - }; - ivs[0] = hp_iv; - ivs[5] = ivs[4]; + if (language == KOR_ID) + { + gen_3_pkmn[18] = JPN_ID; // Set to JPN + byte new_nickname[10]; + byte new_ot[7]; for (int i = 0; i < 6; i++) - { - ivs[i] = (ivs[i] * 2) + 1; - iv_egg_ability |= ((ivs[i] & 0b11111) << (i * 5)); + { // Read the JPN name and convert it + new_nickname[i] = get_gen_3_char(JPN_NAMES[species_index_struct][i], true); } - // Determine and set Ability - iv_egg_ability |= ((pid[0] & 0x1) ? get_num_abilities(species_index_struct) : 0) << 31; - - // Origin info - origin_info |= ((caught_data[1] & 0b10000000) << 8); // OT gender - We would shift left 15 bits, but the bit is already shifted over 7 - origin_info |= (4 << 11); // Ball - origin_info |= (((gen == 1) ? 4 : 7) << 7); // Game - origin_info |= level; // Level met - - // Ribbons and Obedience - // ribbons[2] |= 0b00000100; // Artist Ribbon - ribbons[3] |= 0b10000000; // Fateful Encounter flag - // Personality Value - copy_from_to(&pid[0], &gen_3_pkmn[0], 4, false); - // Trainer ID - copy_from_to(&trainer_id[0], &gen_3_pkmn[4], 2, true); - - // Check if the Pokemon is shiny - if ( // Is shiny - (dvs[1] == 0b10101010) && // Checks if the Speed and Special DVs equal 10 - ((dvs[0] & 0xF) == 0b1010) && // Checks if the Defense DVs equal 10 - (((dvs[0] & 0b11000000) >> 6) | (((dvs[0] & 0b00110000) >> 2) > 7))) // Reorganizes the Attack DV bits so that they will be >7 if the Pokemon is shiny + if (gen == 1) { - secret_id[0] = trainer_id[0] ^ pid[0] ^ pid[2] ^ 0xFF; - secret_id[1] = trainer_id[1] ^ pid[1] ^ pid[3] ^ 0xFF; - // Randomly shift by 16 (maybe) + // レッド (Red) + new_ot[0] = 0x7A; // レ + new_ot[1] = 0xA0; // ッ + new_ot[2] = 0x95; // ド + new_ot[3] = 0xFF; } - else // Not shiny, make sure it isn't + else { - if (((trainer_id[0] ^ secret_id[0] ^ pid[0] ^ pid[2]) == 0) && - ((trainer_id[1] ^ secret_id[1] ^ pid[1] ^ pid[3]) > 7)) + if (((caught_data[1] & 0b10000000) >> 7) == 1) // Checks if the Gen 2 player is male or female { - secret_id[0] = 0xFF; - secret_id[1] = 0xFF; - } - } - copy_from_to(&secret_id[0], &gen_3_pkmn[6], 2, false); // Set SID - - if (language != JPN_ID) // If not JPN, figure out what the default language is - { - language = get_def_lang(); - } - - if (language == KOR_ID) - { - - gen_3_pkmn[18] = JPN_ID; // Set to JPN - byte new_nickname[10]; - byte new_ot[7]; - for (int i = 0; i < 6; i++) - { // Read the JPN name and convert it - new_nickname[i] = get_gen_3_char(JPN_NAMES[species_index_struct][i], true); - } - - if (gen == 1) - { - // レッド (Red) - new_ot[0] = 0x7A; // レ - new_ot[1] = 0xA0; // ッ - new_ot[2] = 0x95; // ド + // クリス (Kurisu) + new_ot[0] = 0x58; // ク + new_ot[1] = 0x78; // リ + new_ot[2] = 0x5D; // ス new_ot[3] = 0xFF; } else { - if (((caught_data[1] & 0b10000000) >> 7) == 1) // Checks if the Gen 2 player is male or female - { - // クリス (Kurisu) - new_ot[0] = 0x58; // ク - new_ot[1] = 0x78; // リ - new_ot[2] = 0x5D; // ス - new_ot[3] = 0xFF; - } - else - { - // ヒビキ (Hibiki) - new_ot[0] = 0x6B; // ヒ - new_ot[1] = 0x97; // ビ - new_ot[2] = 0x57; // キ - new_ot[3] = 0xFF; - } - } - copy_from_to(&new_nickname[0], &gen_3_pkmn[8], 10, false); // Nickname - copy_from_to(&new_ot[0], &gen_3_pkmn[20], 7, false); // OT Name - } - else - { - gen_3_pkmn[18] = language; // Language - copy_from_to(convert_text(&nickname[0], 10, gen, language), &gen_3_pkmn[8], 10, false); // Nickname - copy_from_to(convert_text(&trainer_name[0], 7, gen, language), &gen_3_pkmn[20], 7, false); // OT Name - } - gen_3_pkmn[19] = 0b00000010; // Egg Name (has species sanity flag) - gen_3_pkmn[27] = 0b00000000; // Markings - - // Data: - - // Reset the data sections (in case the player runs the program twice) - for (int i = 0; i < 12; i++) - { - data_section_G[i] = 0; - data_section_A[i] = 0; - data_section_E[i] = 0; - data_section_M[i] = 0; - } - - data_section_G[0] = species_index_struct; - data_section_G[1] = 0x00; // Species Index, check for glitch Pokemon - if (!is_caught(species_index_struct)) - { - data_section_G[2] = 0x44; // Rare Candy - is_new = true; - } - else - { - data_section_G[2] = 0x00; // No item - } - data_section_G[3] = 0x00; - copy_from_to(&exp[0], &data_section_G[4], 3, false); - data_section_G[8] = (pp_bonus[0] << 0 | pp_bonus[1] << 2 | pp_bonus[2] << 4 | pp_bonus[3] << 6); - - data_section_A[0] = moves[0]; // Move 1 - data_section_A[2] = moves[1]; // Move 2 - data_section_A[4] = moves[2]; // Move 3 - data_section_A[6] = moves[3]; // Move 4 - copy_from_to(&pure_pp_values[0], &data_section_A[8], 4, false); // PP Values - - // Data section E is all zero (EVs and Contest Stats) - - data_section_M[0] = pokerus; - data_section_M[1] = 0xFF; // Met location - set to Fateful Encounter (separate from flag), cannot be seen by player and is replaced by Pal Park in gen 4 - data_section_M[2] = origin_info & 0x00FF; // Lower origins info - data_section_M[3] = (origin_info >> 8) & 0xFF; // Upper origins info - for (int i = 0; i < 4; i++) - { - data_section_M[i + 4] = (iv_egg_ability >> (i * 8) & 0xFF); // Set IVs, Egg, and Ability - } - copy_from_to(&ribbons[0], &data_section_M[8], 4, false); // Ribbons and Fateful Encounter - - // Checksum: - checksum = 0x0000; - for (int i = 0; i < 12; i = i + 2) - { - checksum = checksum + ((data_section_G[i + 1] << 8) | data_section_G[i]); - checksum = checksum + ((data_section_A[i + 1] << 8) | data_section_A[i]); - checksum = checksum + ((data_section_E[i + 1] << 8) | data_section_E[i]); - checksum = checksum + ((data_section_M[i + 1] << 8) | data_section_M[i]); - } - - gen_3_pkmn[28] = checksum & 0xFF; - gen_3_pkmn[29] = (checksum & 0xFF00) >> 8; - - for (int i = 0; i < 4; i++) - { - encryption_key[i] = gen_3_pkmn[4 + i] ^ pid[i]; // XOR SID and TID with PID - } - - for (int i = 0; i < 12; i++) - { - unencrypted_data[i] = data_section_G[i]; - data_section_G[i] ^= encryption_key[i % 4]; - unencrypted_data[12 + i] = data_section_A[i]; - data_section_A[i] ^= encryption_key[i % 4]; - unencrypted_data[24 + i] = data_section_E[i]; - data_section_E[i] ^= encryption_key[i % 4]; - unencrypted_data[36 + i] = data_section_M[i]; - data_section_M[i] ^= encryption_key[i % 4]; - } - - // Puts the four data chunks into their correct locations based on the PID - alocate_data_chunks(data_section_G, data_section_A, data_section_E, data_section_M); - } - - void Pokemon::copy_from_to(byte * source, byte * destination, int size, bool reverse_endian) - { - if (reverse_endian) - { - for (int i = 0; i < size; i++) - { - destination[(size - 1) - i] = source[i]; - } - } - else - { - for (int i = 0; i < size; i++) - { - destination[i] = source[i]; + // ヒビキ (Hibiki) + new_ot[0] = 0x6B; // ヒ + new_ot[1] = 0x97; // ビ + new_ot[2] = 0x57; // キ + new_ot[3] = 0xFF; } } + copy_from_to(&new_nickname[0], &gen_3_pkmn[8], 10, false); // Nickname + copy_from_to(&new_ot[0], &gen_3_pkmn[20], 7, false); // OT Name } - - void Pokemon::alocate_data_chunks(byte * G, byte * A, byte * E, byte * M) + else { - word full_pid = (pid[3] << 24 | pid[2] << 16 | pid[1] << 8 | pid[0]); - byte mod_pid = full_pid % 24; - unencrypted_data[48] = mod_pid; - // This is such a stupid way to do this, but I can't for the life of me find a formula for the permutation table. - switch (mod_pid) - { - case 0: - insert_data(G, A, E, M); - break; - case 1: - insert_data(G, A, M, E); - break; - case 2: - insert_data(G, E, A, M); - break; - case 3: - insert_data(G, E, M, A); - break; - case 4: - insert_data(G, M, A, E); - break; - case 5: - insert_data(G, M, E, A); - break; - case 6: - insert_data(A, G, E, M); - break; - case 7: - insert_data(A, G, M, E); - break; - case 8: - insert_data(A, E, G, M); - break; - case 9: - insert_data(A, E, M, G); - break; - case 10: - insert_data(A, M, G, E); - break; - case 11: - insert_data(A, M, E, G); - break; - case 12: - insert_data(E, G, A, M); - break; - case 13: - insert_data(E, G, M, A); - break; - case 14: - insert_data(E, A, G, M); - break; - case 15: - insert_data(E, A, M, G); - break; - case 16: - insert_data(E, M, G, A); - break; - case 17: - insert_data(E, M, A, G); - break; - case 18: - insert_data(M, G, A, E); - break; - case 19: - insert_data(M, G, E, A); - break; - case 20: - insert_data(M, A, G, E); - break; - case 21: - insert_data(M, A, E, G); - break; - case 22: - insert_data(M, E, G, A); - break; - case 23: - insert_data(M, E, A, G); - break; - } + gen_3_pkmn[18] = language; // Language + copy_from_to(convert_text(&nickname[0], 10, gen, language), &gen_3_pkmn[8], 10, false); // Nickname + copy_from_to(convert_text(&trainer_name[0], 7, gen, language), &gen_3_pkmn[20], 7, false); // OT Name } + gen_3_pkmn[19] = 0b00000010; // Egg Name (has species sanity flag) + gen_3_pkmn[27] = 0b00000000; // Markings - void Pokemon::insert_data(byte * first, byte * second, byte * third, byte * fourth) + // Data: + + // Reset the data sections (in case the player runs the program twice) + for (int i = 0; i < 12; i++) { - copy_from_to(&first[0], &gen_3_pkmn[32], 12, false); - copy_from_to(&second[0], &gen_3_pkmn[44], 12, false); - copy_from_to(&third[0], &gen_3_pkmn[56], 12, false); - copy_from_to(&fourth[0], &gen_3_pkmn[68], 12, false); + data_section_G[i] = 0; + data_section_A[i] = 0; + data_section_E[i] = 0; + data_section_M[i] = 0; } - byte Pokemon::get_gen_3_data(int index) + data_section_G[0] = species_index_struct; + data_section_G[1] = 0x00; // Species Index, check for glitch Pokemon + if (!is_caught(species_index_struct)) { - return gen_3_pkmn[index]; + data_section_G[2] = 0x44; // Rare Candy + is_new = true; + set_caught(species_index_struct); } - - byte *Pokemon::get_full_gen_3_array() + else { - return gen_3_pkmn; + data_section_G[2] = 0x00; // No item } + data_section_G[3] = 0x00; + copy_from_to(&exp[0], &data_section_G[4], 3, false); + data_section_G[8] = (pp_bonus[0] << 0 | pp_bonus[1] << 2 | pp_bonus[2] << 4 | pp_bonus[3] << 6); - byte Pokemon::get_unencrypted_data(int index) + data_section_A[0] = moves[0]; // Move 1 + data_section_A[2] = moves[1]; // Move 2 + data_section_A[4] = moves[2]; // Move 3 + data_section_A[6] = moves[3]; // Move 4 + copy_from_to(&pure_pp_values[0], &data_section_A[8], 4, false); // PP Values + + // Data section E is all zero (EVs and Contest Stats) + + data_section_M[0] = pokerus; + data_section_M[1] = 0xFF; // Met location - set to Fateful Encounter (separate from flag), cannot be seen by player and is replaced by Pal Park in gen 4 + data_section_M[2] = origin_info & 0x00FF; // Lower origins info + data_section_M[3] = (origin_info >> 8) & 0xFF; // Upper origins info + for (int i = 0; i < 4; i++) { - return unencrypted_data[index]; + data_section_M[i + 4] = (iv_egg_ability >> (i * 8) & 0xFF); // Set IVs, Egg, and Ability + } + copy_from_to(&ribbons[0], &data_section_M[8], 4, false); // Ribbons and Fateful Encounter + + // Checksum: + checksum = 0x0000; + for (int i = 0; i < 12; i = i + 2) + { + checksum = checksum + ((data_section_G[i + 1] << 8) | data_section_G[i]); + checksum = checksum + ((data_section_A[i + 1] << 8) | data_section_A[i]); + checksum = checksum + ((data_section_E[i + 1] << 8) | data_section_E[i]); + checksum = checksum + ((data_section_M[i + 1] << 8) | data_section_M[i]); } - byte *Pokemon::convert_text(byte * text_array, int size, int gen, int lang) + gen_3_pkmn[28] = checksum & 0xFF; + gen_3_pkmn[29] = (checksum & 0xFF00) >> 8; + + for (int i = 0; i < 4; i++) + { + encryption_key[i] = gen_3_pkmn[4 + i] ^ pid[i]; // XOR SID and TID with PID + } + + for (int i = 0; i < 12; i++) + { + unencrypted_data[i] = data_section_G[i]; + data_section_G[i] ^= encryption_key[i % 4]; + unencrypted_data[12 + i] = data_section_A[i]; + data_section_A[i] ^= encryption_key[i % 4]; + unencrypted_data[24 + i] = data_section_E[i]; + data_section_E[i] ^= encryption_key[i % 4]; + unencrypted_data[36 + i] = data_section_M[i]; + data_section_M[i] ^= encryption_key[i % 4]; + } + + // Puts the four data chunks into their correct locations based on the PID + alocate_data_chunks(data_section_G, data_section_A, data_section_E, data_section_M); +} + +void Pokemon::copy_from_to(byte *source, byte *destination, int size, bool reverse_endian) +{ + if (reverse_endian) { for (int i = 0; i < size; i++) { - switch (gen) + destination[(size - 1) - i] = source[i]; + } + } + else + { + for (int i = 0; i < size; i++) + { + destination[i] = source[i]; + } + } +} + +void Pokemon::alocate_data_chunks(byte *G, byte *A, byte *E, byte *M) +{ + word full_pid = (pid[3] << 24 | pid[2] << 16 | pid[1] << 8 | pid[0]); + byte mod_pid = full_pid % 24; + unencrypted_data[48] = mod_pid; + // This is such a stupid way to do this, but I can't for the life of me find a formula for the permutation table. + switch (mod_pid) + { + case 0: + insert_data(G, A, E, M); + break; + case 1: + insert_data(G, A, M, E); + break; + case 2: + insert_data(G, E, A, M); + break; + case 3: + insert_data(G, E, M, A); + break; + case 4: + insert_data(G, M, A, E); + break; + case 5: + insert_data(G, M, E, A); + break; + case 6: + insert_data(A, G, E, M); + break; + case 7: + insert_data(A, G, M, E); + break; + case 8: + insert_data(A, E, G, M); + break; + case 9: + insert_data(A, E, M, G); + break; + case 10: + insert_data(A, M, G, E); + break; + case 11: + insert_data(A, M, E, G); + break; + case 12: + insert_data(E, G, A, M); + break; + case 13: + insert_data(E, G, M, A); + break; + case 14: + insert_data(E, A, G, M); + break; + case 15: + insert_data(E, A, M, G); + break; + case 16: + insert_data(E, M, G, A); + break; + case 17: + insert_data(E, M, A, G); + break; + case 18: + insert_data(M, G, A, E); + break; + case 19: + insert_data(M, G, E, A); + break; + case 20: + insert_data(M, A, G, E); + break; + case 21: + insert_data(M, A, E, G); + break; + case 22: + insert_data(M, E, G, A); + break; + case 23: + insert_data(M, E, A, G); + break; + } +} + +void Pokemon::insert_data(byte *first, byte *second, byte *third, byte *fourth) +{ + copy_from_to(&first[0], &gen_3_pkmn[32], 12, false); + copy_from_to(&second[0], &gen_3_pkmn[44], 12, false); + copy_from_to(&third[0], &gen_3_pkmn[56], 12, false); + copy_from_to(&fourth[0], &gen_3_pkmn[68], 12, false); +} + +byte Pokemon::get_gen_3_data(int index) +{ + return gen_3_pkmn[index]; +} + +byte *Pokemon::get_full_gen_3_array() +{ + return gen_3_pkmn; +} + +byte Pokemon::get_unencrypted_data(int index) +{ + return unencrypted_data[index]; +} + +byte *Pokemon::convert_text(byte *text_array, int size, int gen, int lang) +{ + for (int i = 0; i < size; i++) + { + switch (gen) + { + case 1: + switch (lang) { - case 1: - switch (lang) - { - case JPN_ID: - text_array[i] = get_gen_3_char(gen_1_Jpn_char_array[text_array[i]], true); - break; - case ENG_ID: - default: - text_array[i] = get_gen_3_char(gen_1_Eng_char_array[text_array[i]], false); - break; - case FRE_ID: - case GER_ID: - text_array[i] = get_gen_3_char(gen_1_FreGer_char_array[text_array[i]], false); - break; - case SPA_ID: - case ITA_ID: - text_array[i] = get_gen_3_char(gen_1_ItaSpa_char_array[text_array[i]], false); - break; - } + case JPN_ID: + text_array[i] = get_gen_3_char(gen_1_Jpn_char_array[text_array[i]], true); break; - case 2: + case ENG_ID: default: - switch (lang) - { - case JPN_ID: - text_array[i] = get_gen_3_char(gen_2_Jpn_char_array[text_array[i]], true); - break; - case ENG_ID: - default: - text_array[i] = get_gen_3_char(gen_2_Eng_char_array[text_array[i]], false); - break; - case FRE_ID: - case GER_ID: - text_array[i] = get_gen_3_char(gen_2_FreGer_char_array[text_array[i]], false); - break; - case SPA_ID: - case ITA_ID: - text_array[i] = get_gen_3_char(gen_2_ItaSpa_char_array[text_array[i]], false); - break; - } + text_array[i] = get_gen_3_char(gen_1_Eng_char_array[text_array[i]], false); + break; + case FRE_ID: + case GER_ID: + text_array[i] = get_gen_3_char(gen_1_FreGer_char_array[text_array[i]], false); + break; + case SPA_ID: + case ITA_ID: + text_array[i] = get_gen_3_char(gen_1_ItaSpa_char_array[text_array[i]], false); break; } - } - return text_array; - } - - u32 Pokemon::generate_pid(byte pid_species_index, byte nature, byte * pid_dvs) - { - // Set Unown Letter - u32 new_pid = 0; - byte letter = 0; - if (pid_species_index == 0xC9) // Checks if the Pokemon is Unown - { - letter |= ((pid_dvs[0] >> 5) & 0b11) << 6; - letter |= ((pid_dvs[0] >> 1) & 0b11) << 4; - letter |= ((pid_dvs[1] >> 5) & 0b11) << 2; - letter |= ((pid_dvs[1] >> 1) & 0b11); - letter = letter / 10; - - byte letter_mod = rand_reverse_mod(28, letter); - for (int i = 0; i < 4; i++) + break; + case 2: + default: + switch (lang) { - new_pid |= ((letter_mod >> (i * 2)) & 0b11) << (8 * i); + case JPN_ID: + text_array[i] = get_gen_3_char(gen_2_Jpn_char_array[text_array[i]], true); + break; + case ENG_ID: + default: + text_array[i] = get_gen_3_char(gen_2_Eng_char_array[text_array[i]], false); + break; + case FRE_ID: + case GER_ID: + text_array[i] = get_gen_3_char(gen_2_FreGer_char_array[text_array[i]], false); + break; + case SPA_ID: + case ITA_ID: + text_array[i] = get_gen_3_char(gen_2_ItaSpa_char_array[text_array[i]], false); + break; } - - // Randomize rest of PID - new_pid |= get_rand_u32() & 0xFCFCFCFC; - - // Set Nature - while ((new_pid % 25) != nature) - { - // Keep adding 0b100 to the PID until the nature matches - // 0b100 ensures that the 2 LSBs are maintained, as they determine the letter - new_pid = (new_pid & 0xFFFFFF00) | ((new_pid + 0b100) & 0xFF); - } - return new_pid; + break; } - else + } + return text_array; +} + +u32 Pokemon::generate_pid(byte pid_species_index, byte nature, byte *pid_dvs) +{ + // Set Unown Letter + u32 new_pid = 0; + byte letter = 0; + if (pid_species_index == 0xC9) // Checks if the Pokemon is Unown + { + letter |= ((pid_dvs[0] >> 5) & 0b11) << 6; + letter |= ((pid_dvs[0] >> 1) & 0b11) << 4; + letter |= ((pid_dvs[1] >> 5) & 0b11) << 2; + letter |= ((pid_dvs[1] >> 1) & 0b11); + letter = letter / 10; + + byte letter_mod = rand_reverse_mod(28, letter); + for (int i = 0; i < 4; i++) { - // Set the correct gender for the Pokemon - new_pid |= get_rand_gender_byte(pid_species_index, ((pid_dvs[0] >> 4) & 0b1111)); - - // Randomize rest of PID - new_pid |= get_rand_u32() & 0xFFFFFF00; - - // Set nature - while (new_pid % 25 != nature) - { - new_pid = new_pid + 256; - } - return new_pid; + new_pid |= ((letter_mod >> (i * 2)) & 0b11) << (8 * i); } - } - byte Pokemon::rand_reverse_mod(byte modulo_divisor, byte target_mod) - { - return (modulo_divisor * get_rand_range(0, (255 - target_mod) / modulo_divisor)) + target_mod; - } + // Randomize rest of PID + new_pid |= get_rand_u32() & 0xFCFCFCFC; - byte Pokemon::get_rand_gender_byte(byte index_num, byte attack_DVs) - { - byte gen2_threshold = get_gender_threshold(index_num, false); - byte gen3_threshold = get_gender_threshold(index_num, true); - if (gen2_threshold == -1) // Is one gender or is genderless + // Set Nature + while ((new_pid % 25) != nature) { - return get_rand_range(0, 256); + // Keep adding 0b100 to the PID until the nature matches + // 0b100 ensures that the 2 LSBs are maintained, as they determine the letter + new_pid = (new_pid & 0xFFFFFF00) | ((new_pid + 0b100) & 0xFF); } - else if (attack_DVs < gen2_threshold) // Is Female + return new_pid; + } + else + { + // Set the correct gender for the Pokemon + new_pid |= get_rand_gender_byte(pid_species_index, ((pid_dvs[0] >> 4) & 0b1111)); + + // Randomize rest of PID + new_pid |= get_rand_u32() & 0xFFFFFF00; + + // Set nature + while (new_pid % 25 != nature) { - return get_rand_range(0, gen3_threshold); - } - else // Is Male - { - return get_rand_range(gen3_threshold, 256); + new_pid = new_pid + 256; } + return new_pid; } +} - byte Pokemon::get_dex_number() +byte Pokemon::rand_reverse_mod(byte modulo_divisor, byte target_mod) +{ + return (modulo_divisor * get_rand_range(0, (255 - target_mod) / modulo_divisor)) + target_mod; +} + +byte Pokemon::get_rand_gender_byte(byte index_num, byte attack_DVs) +{ + byte gen2_threshold = get_gender_threshold(index_num, false); + byte gen3_threshold = get_gender_threshold(index_num, true); + if (gen2_threshold == -1) // Is one gender or is genderless { - return species_index_struct; + return get_rand_range(0, 256); } - - bool Pokemon::get_validity() + else if (attack_DVs < gen2_threshold) // Is Female { - return is_valid; + return get_rand_range(0, gen3_threshold); } - - bool Pokemon::get_is_new() + else // Is Male { - return is_new; - } \ No newline at end of file + return get_rand_range(gen3_threshold, 256); + } +} + +byte Pokemon::get_dex_number() +{ + return species_index_struct; +} + +bool Pokemon::get_validity() +{ + return is_valid; +} + +bool Pokemon::get_is_new() +{ + return is_new; +} \ No newline at end of file diff --git a/source/pokemon_party.cpp b/source/pokemon_party.cpp index c6eb412..9b9aa5a 100644 --- a/source/pokemon_party.cpp +++ b/source/pokemon_party.cpp @@ -5,46 +5,15 @@ #include "debug_mode.h" #include "mystery_gift_injector.h" -/* -byte debug_party_data[GEN2_INT_SIZE + 4] = { // Japanese Gen 1 - 0x07, 0xD8, 0xE3, 0xAB, 0x50, 0x8B, - 0x06, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0xFF, - 0x01, 0x00, 0x14, 0x00, 0x00, 0x15, 0x15, 0x2D, 0x21, 0x27, 0x00, 0x00, 0x2E, 0x75, 0x00, 0x00, 0xCA, 0x00, 0x2D, 0x00, 0x31, 0x00, 0x31, 0x00, 0x2D, 0x00, 0x41, 0x59, 0x19, 0x23, 0x1D, 0x00, 0x00, 0x06, 0x00, 0x17, 0x00, 0x0B, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x0C, - 0x02, 0x00, 0x17, 0x06, 0x00, 0x15, 0x15, 0x2D, 0x21, 0x27, 0x00, 0x00, 0x2E, 0x75, 0x00, 0x00, 0xCA, 0x00, 0x2D, 0x00, 0x31, 0x00, 0x31, 0x00, 0x2D, 0x00, 0x41, 0x59, 0x19, 0x23, 0x1D, 0x00, 0x00, 0x06, 0x00, 0x17, 0x00, 0x0B, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x0C, - 0x03, 0x00, 0x17, 0x06, 0x00, 0x15, 0x15, 0x2D, 0x21, 0x27, 0x00, 0x00, 0x2E, 0x75, 0x00, 0x00, 0xCA, 0x00, 0x2D, 0x00, 0x31, 0x00, 0x31, 0x00, 0x2D, 0x00, 0x41, 0x59, 0x19, 0x23, 0x1D, 0x00, 0x00, 0x06, 0x00, 0x17, 0x00, 0x0B, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x0C, - 0x04, 0x00, 0x17, 0x06, 0x00, 0x15, 0x15, 0x2D, 0x21, 0x27, 0x00, 0x00, 0x2E, 0x75, 0x00, 0x00, 0xCA, 0x00, 0x2D, 0x00, 0x31, 0x00, 0x31, 0x00, 0x2D, 0x00, 0x41, 0x59, 0x19, 0x23, 0x1D, 0x00, 0x00, 0x06, 0x00, 0x17, 0x00, 0x0B, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x0C, - 0x05, 0x00, 0x17, 0x06, 0x00, 0x15, 0x15, 0x2D, 0x21, 0x27, 0x00, 0x00, 0x2E, 0x75, 0x00, 0x00, 0xCA, 0x00, 0x2D, 0x00, 0x31, 0x00, 0x31, 0x00, 0x2D, 0x00, 0x41, 0x59, 0x19, 0x23, 0x1D, 0x00, 0x00, 0x06, 0x00, 0x17, 0x00, 0x0B, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x0C, - 0x06, 0x00, 0x17, 0x06, 0x00, 0x15, 0x15, 0x2D, 0x21, 0x27, 0x00, 0x00, 0x2E, 0x75, 0x00, 0x00, 0xCA, 0x00, 0x2D, 0x00, 0x31, 0x00, 0x31, 0x00, 0x2D, 0x00, 0x41, 0x59, 0x19, 0x23, 0x1D, 0x00, 0x00, 0x06, 0x00, 0x17, 0x00, 0x0B, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x0C, - - 0x07, 0xD8, 0xE3, 0xAB, 0x50, 0x8B, - 0x07, 0xD8, 0xE3, 0xAB, 0x50, 0x8B, - 0x07, 0xD8, 0xE3, 0xAB, 0x50, 0x8B, - 0x07, 0xD8, 0xE3, 0xAB, 0x50, 0x8B, - 0x07, 0xD8, 0xE3, 0xAB, 0x50, 0x8B, - 0x07, 0xD8, 0xE3, 0xAB, 0x50, 0x8B, - - 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, - - 0x40, 0x00, 0x00, - 0xFD, 0xFD, 0xFD, 0xFD}; -*/ - -byte debug_box_data[0x467] = { +byte debug_box_data[0x462] = { // Preamble - 0x00, 0x00, 0xFD, 0xFD, 0xFD, + //0x00, 0x00, 0xFD, 0xFD, 0xFD, // num of Pokemon - 0x14, + 0x14, // Pokemon 1-20 - 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x70, 0x71, 0x7B, 0x71, 0x71, 0x7C, 0x71, 0x71, 0x71, 0x71, 0x24, 0x24, 0xA5, 0x24, 0xFF, + 0x02, 0x70, 0x70, 0x70, 0x71, 0x71, 0x70, 0x71, 0x7B, 0x71, 0x71, 0x7C, 0x71, 0x71, 0x71, 0x71, 0x24, 0x24, 0xA5, 0x24, 0xFF, // Pokemon list - 0x70, 0x00, 0x11, 0x04, 0x00, 0x07, 0x03, 0xFF, 0x28, 0x51, 0x00, 0x00, 0x6F, 0xC6, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xDE, 0x23, 0x28, 0x00, 0x00, + 0x02, 0x00, 0x11, 0x04, 0x00, 0x07, 0x03, 0xFF, 0x28, 0x51, 0x00, 0x00, 0x6F, 0xC6, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xDE, 0x23, 0x28, 0x00, 0x00, 0x70, 0x00, 0x12, 0x04, 0x00, 0x07, 0x03, 0xFF, 0x28, 0x51, 0x00, 0x00, 0x6F, 0xC6, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xD8, 0x23, 0x28, 0x00, 0x00, 0x70, 0x00, 0x12, 0x04, 0x00, 0x07, 0x03, 0xFF, 0x28, 0x51, 0x00, 0x00, 0x6F, 0xC6, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x13, 0x23, 0x28, 0x00, 0x00, 0x70, 0x00, 0x0F, 0x03, 0x00, 0x07, 0x03, 0xFF, 0x28, 0x51, 0x00, 0x00, 0x6F, 0xC6, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0x81, 0x23, 0x28, 0x00, 0x00, @@ -108,11 +77,12 @@ byte debug_box_data[0x467] = { 0x8F, 0x88, 0x83, 0x86, 0x84, 0x98, 0x50, 0x50, 0x50, 0x50, 0x50, }; Pokemon_Party::Pokemon_Party(){}; + void Pokemon_Party::start_link() { if (IGNORE_LINK_CABLE) { - for (int i = 0; i < GEN2_INT_SIZE + 4; i++) + for (int i = 0; i < BOX_DATA_ARRAY_SIZE; i++) { box_data_array[i] = debug_box_data[i]; } @@ -122,7 +92,7 @@ void Pokemon_Party::start_link() setup(); last_error = loop(&box_data_array[0]); } - num_pokemon = 0x06; + num_pokemon = 6; } int Pokemon_Party::get_last_error() @@ -135,7 +105,7 @@ Pokemon Pokemon_Party::get_converted_pkmn(int index) Pokemon converted_mon; converted_mon.load_data(index, box_data_array, game, lang); converted_mon.convert_to_gen_three(); - has_new_pkmn = converted_mon.get_is_new() || has_new_pkmn; + has_new_pkmn = has_new_pkmn || converted_mon.get_is_new(); return converted_mon; } diff --git a/source/script_array.cpp b/source/script_array.cpp index 781e5c2..efdf09a 100644 --- a/source/script_array.cpp +++ b/source/script_array.cpp @@ -8,7 +8,7 @@ #include int last_error; -Pokemon_Party party_data; +Pokemon_Party party_data = Pokemon_Party(); script_obj script[SCRIPT_SIZE]; std::string_view dialogue[DIA_SIZE]; @@ -90,11 +90,6 @@ void populate_script() script[CMD_BACK_TO_MENU] = script_obj(CMD_BACK_TO_MENU, SCRIPT_START); }; -void add_script_party_var(Pokemon_Party var) -{ - party_data = var; -} - bool run_conditional(int index) { // Here is most of the logic that drives what lines show up where. It's probably not the best way to code it, but it works