diff --git a/payload_builder copy.cpp b/payload_builder copy.cpp deleted file mode 100644 index 3cf5357..0000000 --- a/payload_builder copy.cpp +++ /dev/null @@ -1,996 +0,0 @@ -#include "payloads/payload_builder.h" -#include "gb_rom_values/base_gb_rom_struct.h" -#include "payloads/z80_asm.h" -#include "../../../include/debug_mode.h" -#include - -#define DATA_LOC (SHOW_DATA_PACKETS ? curr_rom.transferStringLocation : curr_rom.wEnemyMonSpecies) -#define DEBUG_PAYLOADS (false && DEBUG_MODE) - -void init_payload(byte *payload_buffer, const GB_ROM &curr_rom, int type, bool debug) -{ - if (DEBUG_PAYLOADS) - { - debug = true; - } - - (void)type; - /* 10 RNG bytes - 8 Preamble bytes - 418 / 441 Party bytes - 7 Preamble bytes - 194 Patch list bytes (last 2 are unused) - - 637 / 660 total bytes - */ - if ((curr_rom.generation == 1 && curr_rom.version != YELLOW_ID)) - { - std::vector jump_vector; - std::vector var_vector; - - z80_asm_handler z80_rng_seed(0x0A, curr_rom.wSerialOtherGameboyRandomNumberListBlock + 8); - z80_asm_handler z80_payload(0x1AA, curr_rom.wSerialEnemyDataBlock); - z80_asm_handler z80_patchlist(0xC9, curr_rom.wSerialEnemyMonsPatchList); - - z80_jump asm_start(&jump_vector); - z80_jump save_box(&jump_vector); - z80_jump remove_array_loop(&jump_vector); - z80_jump packet_loop(&jump_vector); - z80_jump fe_bypass(&jump_vector); - z80_jump send_packet_loop(&jump_vector); - - z80_variable array_counter(&var_vector, 1, 0x00); // 1 byte to store the current array counter - z80_variable removal_array(&var_vector); // 40 byte storage for list of Pokemon to remove, plus a permanent array terminator - - byte removal_array_data[41]; - for (int i = 0; i < 41; i++) - { - if (debug) - { - removal_array_data[i] = (i < 30 ? (29 - i) : 0xFF); - } - else - { - removal_array_data[i] = (i < 30 ? 0xFD : 0xFF); - } - } - removal_array.load_data(41, removal_array_data); - z80_variable transfer_wait_string(&var_vector, 13, // SENDING DATA - 0x92, 0x84, 0x8D, 0x83, 0x88, 0x8D, 0x86, 0x7F, 0x83, 0x80, 0x93, 0x80, 0x50); - z80_variable custom_name(&var_vector, 11, // FENNEL - 0x85, 0x84, 0x8D, 0x8D, 0x84, 0x8B, 0x50, 0x50, 0x50, 0x50, 0x50); - - // RNG Seed - // Location of the entrance vector - z80_rng_seed.index = 5; // Set the entrance vector - z80_rng_seed.JP(asm_start.place_direct_jump(&z80_rng_seed) | T_U16); - - // Preamble - // At 0x00, 0x07 in length - // Must be filled with 0xFD - for (int i = 0; i < 7; i++) - { - z80_payload.add_byte(0xFD); - } - - // Rival name - // At 0x07, 0x0B in length - // Set to stored name - z80_payload.index = 0x07; - custom_name.insert_variable(&z80_payload); - - // Number of Pokemon - // At 0x12, 0x01 in length - // Does not need to be set - z80_payload.index = 0x12; - z80_payload.add_byte(0x06); - - // Pokemon list - // At 0x13, can be up to 0x1A2 / 0x1B9 bytes in length. - // Calculate the number of Pokemon names that need to be printed, - // and add them to the list. Then terminate the list. - z80_payload.index = 0x13; - int distance = curr_rom.stack_overwrite_location - curr_rom.print_string_start; - distance /= 20; // Automatically truncated, so it won't overshoot - - for (int i = 0; i < distance; i++) - { - z80_payload.add_byte(curr_rom.short_pkmn_name); - } - z80_payload.add_byte(curr_rom.pointer_pkmn_name); - z80_payload.add_byte(0xFF); - - // Patchlist preamble - // At 0x1B4 / 0x1D7, 0x07 in length - // Set as five 0xFD and two 0xFF - - for (int i = 0; i < 7; i++) - { - z80_patchlist.add_byte(i < 5 ? 0xFD : 0xFF); - } - - // Patchlist - // At 0x1BB / 0x1DE, 0xC2 in length (0xC4, but the last 2 are unused) - // Fill with custom code - asm_start.set_start(&z80_patchlist); - - /* Write transferring message to screen: */ - // call ClearScreen - z80_patchlist.CALL(curr_rom.clearScreen | T_U16); - z80_patchlist.LD(HL, curr_rom.textBorderUppLeft | T_U16); - z80_patchlist.LD(C, curr_rom.textBorderWidth | T_U8); - z80_patchlist.LD(B, curr_rom.textBorderHeight | T_U8); - z80_patchlist.CALL(curr_rom.CableClub_TextBoxBorder | T_U16); - z80_patchlist.LD(HL, curr_rom.transferStringLocation | T_U16); - z80_patchlist.LD(DE, transfer_wait_string.place_ptr(&z80_patchlist) | T_U16); - z80_patchlist.CALL(curr_rom.placeString | T_U16); - - /* Build the packet */ - // HL is the current data pointer - // DE is the destination pointer - // A is the checksum - // B is the 0xFE flag byte - // C is the counter - send_packet_loop.set_start(&z80_patchlist); - - z80_patchlist.LD(HL, (DATA_LOC + PACKET_SIZE + 3) | T_U16); // Load the next data location into HL - z80_patchlist.LD(A, HLI_PTR); - z80_patchlist.LD(H, HL_PTR); - z80_patchlist.LD(L, A); - z80_patchlist.LD(DE, (DATA_LOC + 2) | T_U16); // Enemy Pokemon data, should be unused - z80_patchlist.XOR(A, A); // Clear the register - z80_patchlist.LD(B, A); // Clear B as well - z80_patchlist.LD(C, A); // Clear C as well - z80_patchlist.PUSH(AF); - packet_loop.set_start(&z80_patchlist); - z80_patchlist.LD(B, 0x00 | T_U8); // Reset the flag byte - z80_patchlist.POP(AF); - z80_patchlist.ADD(A, HL_PTR); // Add the current data to the checksum - z80_patchlist.PUSH(AF); - z80_patchlist.LD(A, 0xFE); - z80_patchlist.CP(A, HL_PTR); // Compare the current data to 0xFE - z80_patchlist.LD(A, HLI_PTR); // Load HL's data into A for modification (if need be) - - // If HL's data is 0xFE - z80_patchlist.JR(NZ_F, fe_bypass.place_relative_jump(&z80_patchlist) | T_I8); - z80_patchlist.DEC(A); - z80_patchlist.INC(B); // Set flag - - fe_bypass.set_start(&z80_patchlist); - z80_patchlist.LD(DE_PTR, A); // Place the data in - z80_patchlist.INC(DE); - z80_patchlist.PUSH(AF); - z80_patchlist.LD(A, B); - z80_patchlist.LD(DE_PTR, A); // Place the flag in as well - z80_patchlist.POP(AF); - z80_patchlist.INC(DE); - z80_patchlist.INC(C); - z80_patchlist.LD(A, DATA_PER_PACKET - 1); - z80_patchlist.CP(A, C); - z80_patchlist.JR(NC_F, packet_loop.place_relative_jump(&z80_patchlist) | T_I8); // If all the data has been set, send the rest of the data - z80_patchlist.POP(AF); - z80_patchlist.RES(7 | T_BIT, A); // Reset bit 7 of the checksum, guaranteeing that it will never be 0xFE - z80_patchlist.LD(DE_PTR, A); - z80_patchlist.INC(DE); - z80_patchlist.LD(A, H); - z80_patchlist.LD(DE_PTR, A); - z80_patchlist.INC(DE); - z80_patchlist.LD(A, L); - z80_patchlist.LD(DE_PTR, A); - - // z80_patchlist.LD(HL, curr_rom.garbageDataLocation | T_U16); - - /* Transfer box data packet: */ - z80_patchlist.LD(A, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug - z80_patchlist.LDH((curr_rom.hSerialConnectionStatus & 0xFF) | T_U8, A); // Since hSerialConnectionStatus is at 0xFFxx we can use this method instead - z80_patchlist.LD(HL, DATA_LOC | T_U16); - z80_patchlist.LD(HL_PTR, 0xFD | T_U8); // set the start of the data to 0xFD so Serial_ExchangeBytes is happy - z80_patchlist.INC(HL); - z80_patchlist.LD(HL_PTR, 0x00 | T_U8); // add a 0x00 after the 0xFD to prevent further 0xFDs from being interpreted as part of the preamble - z80_patchlist.DEC(HL); // Reset HL back so it points to 0xFD - z80_patchlist.LD(DE, (DATA_LOC + PACKET_SIZE) | T_U16); // location to put stored data - z80_patchlist.LD(BC, PACKET_SIZE | T_U16); - if (debug) // Don't call serialExchangeBytes if debug is enabled - { - z80_patchlist.index += 3; - } - else - { - z80_patchlist.CALL(curr_rom.Serial_ExchangeBytes | T_U16); - } - - z80_patchlist.LD(A, (DATA_LOC + PACKET_SIZE + 3 + 1) | T_U16); - z80_patchlist.CP(A, 0xFF); - z80_patchlist.JR(NZ_F, send_packet_loop.place_relative_jump(&z80_patchlist) | T_I8); - - /* Recieve the Pokemon to remove */ - z80_patchlist.LD(HL, curr_rom.hSerialConnectionStatus | T_U16); // This can also be shortened - z80_patchlist.LD(HL_PTR, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug - z80_patchlist.LD(HL, curr_rom.garbageDataLocation | T_U16); - z80_patchlist.LD(DE, removal_array.place_ptr(&z80_patchlist) | T_U16); - z80_patchlist.LD(BC, 0x001E | T_U16); // Preamble does *not* count - if (debug) // Don't add in the Serial_ExchangeBytes call if in debug - { - z80_patchlist.index += 3; - } - else - { - z80_patchlist.CALL(curr_rom.Serial_ExchangeBytes | T_U16); - } - - /* Remove the transfered Pokemon */ - z80_patchlist.LD(HL, curr_rom.wRemoveMonFromBox | T_U16); - z80_patchlist.LD(HL_PTR, 0x01 | T_U8); // != 0x00 specifies the current box - remove_array_loop.set_start(&z80_patchlist); - z80_patchlist.LD(A, array_counter.place_ptr(&z80_patchlist) | T_U16); - z80_patchlist.LD(E, A); - z80_patchlist.LD(D, 0x00 | T_U8); - z80_patchlist.LD(HL, removal_array.place_ptr(&z80_patchlist) | T_U16); - z80_patchlist.ADD(HL, DE); - z80_patchlist.INC(A); - z80_patchlist.LD(array_counter.place_ptr(&z80_patchlist) | T_U16, A); - z80_patchlist.LD(A, curr_rom.wBoxCount | T_U16); - z80_patchlist.LD(B, A); - z80_patchlist.LD(A, HL_PTR); - z80_patchlist.CP(A, 0xFF | T_U8); - z80_patchlist.JR(Z_F, save_box.place_relative_jump(&z80_patchlist) | T_I8); - z80_patchlist.CP(A, B); - z80_patchlist.JR(NC_F, remove_array_loop.place_relative_jump(&z80_patchlist) | T_I8); - z80_patchlist.LD(HL, curr_rom.wWhichPokemon | T_U16); - z80_patchlist.LD(HL_PTR, A); - if (DONT_REMOVE_PKMN) - { - z80_patchlist.index += 3; - } - else - { - z80_patchlist.CALL(curr_rom._RemovePokemon | T_U16); - } - z80_patchlist.JR((remove_array_loop.place_relative_jump(&z80_patchlist) & 0xFF) | T_I8); - - /* Save the current box */ - save_box.set_start(&z80_patchlist); - z80_patchlist.LD(B, (curr_rom.SaveSAVtoSRAM1 >> 16) | T_U8); // Load ROM Bank - z80_patchlist.LD(HL, curr_rom.SaveSAVtoSRAM1 | T_U16); - z80_patchlist.CALL(curr_rom.Bankswitch | T_U16); - z80_patchlist.LD(B, (curr_rom.SaveSAVtoSRAM1 >> 16) | T_U8); // Load ROM Bank - z80_patchlist.LD(HL, curr_rom.SaveSAVtoSRAM2 | T_U16); // TODO: We probably don't have to load the ROM bank twice - z80_patchlist.CALL(curr_rom.Bankswitch | T_U16); - z80_patchlist.JP(curr_rom.SoftReset | T_U16); - - // z80_patchlist.index += 5; - - array_counter.insert_variable(&z80_patchlist); - removal_array.insert_variable(&z80_payload); - transfer_wait_string.insert_variable(&z80_patchlist); - - // This payload works by placing Pokemon ID 0xFC's name in the stack, and causing a return to CD8E, - // which is part of the RNG seed. From there we can jump anywhere- and we choose to jump to D887, - // which is the rival's name. This code fixes the stack and jumps to the patchlist, which is where - // our final code is. - - // Update all the pointers - for (unsigned int i = 0; i < var_vector.size(); i++) - { - var_vector.at(i)->update_ptrs(); - } - for (unsigned int i = 0; i < jump_vector.size(); i++) - { - jump_vector.at(i)->update_jumps(); - } - - // Combine the vectors into the full payload - u8 *cur_out = payload_buffer; - memcpy(cur_out, z80_rng_seed.data_vector.data(), z80_rng_seed.data_vector.size()); - cur_out += z80_rng_seed.data_vector.size(); - memcpy(cur_out, z80_payload.data_vector.data(), z80_payload.data_vector.size()); - cur_out += z80_payload.data_vector.size(); - memcpy(cur_out, z80_patchlist.data_vector.data(), z80_patchlist.data_vector.size()); - cur_out += z80_patchlist.data_vector.size(); - - return; - } - - else if ((curr_rom.generation == 1 && curr_rom.version == YELLOW_ID)) - { - std::vector jump_vector; - std::vector var_vector; - - z80_asm_handler z80_rng_seed(0x0A, curr_rom.wSerialOtherGameboyRandomNumberListBlock + 8); - z80_asm_handler z80_payload(0x1AA, curr_rom.wSerialEnemyDataBlock - 8); // Subtracting 8 is because the data is shifted after patching, removing part of the enemy name. May change depending on language - z80_asm_handler z80_patchlist(0xC9, curr_rom.wSerialEnemyMonsPatchList); - - z80_jump asm_start(&jump_vector); - z80_jump save_box(&jump_vector); - z80_jump remove_array_loop(&jump_vector); - z80_jump packet_loop(&jump_vector); - z80_jump fe_bypass(&jump_vector); - z80_jump send_packet_loop(&jump_vector); - z80_jump skip_enemy_write(&jump_vector); - - z80_jump test_loop(&jump_vector); - - z80_variable array_counter(&var_vector, 1, 0x00); // 1 byte to store the current array counter - z80_variable removal_array(&var_vector); // 40 byte storage for list of Pokemon to remove, plus a permanent array terminator - - byte removal_array_data[41]; - for (int i = 0; i < 41; i++) - { - if (debug) - { - removal_array_data[i] = (i < 30 ? (29 - i) : 0xFF); - } - else - { - removal_array_data[i] = (i < 30 ? 0xFD : 0xFF); - } - } - removal_array.load_data(41, removal_array_data); - z80_variable transfer_wait_string(&var_vector, 13, // SENDING DATA - 0x92, 0x84, 0x8D, 0x83, 0x88, 0x8D, 0x86, 0x7F, 0x83, 0x80, 0x93, 0x80, 0x50); - z80_variable custom_name(&var_vector, 11, // FENNEL - 0x85, 0x84, 0x8D, 0x8D, 0x84, 0x8B, 0x50, 0x50, 0x50, 0x50, 0x50); - - // RNG Seed: - // at 0x00, 0x0A in length - // Can be empty - - // Preamble - // At 0x00, 0x07 in length - // Must be filled with 0xFD - for (int i = 0; i < 7; i++) - { - z80_payload.add_byte(0xFD); - } - - // Rival name - // At 0x07, 0x0B in length - // Set to stored name - z80_payload.index = 0x07; - custom_name.insert_variable(&z80_payload); - - // Number of Pokemon - // At 0x12, 0x01 in length - // 2 or higher, 0xE8 for JPN - z80_payload.index = 0x12; - z80_payload.add_byte(0x02); - - // Pokemon list - // At 0x13, is usually 6 bytes and 1 terminator - for (int i = 0; i < 7; i++) - { - z80_payload.add_byte(i < 6 ? i + 1 : 0xFF); - } - - // Pokemon data - // Specific for each language - - // Mon #1 HP - z80_payload.add_bytes(2, - 0x00, 0x00); - - // Mon #2 data - z80_payload.index = 0x46; - z80_payload.add_bytes(9, - 0x4E, 0x4E, 0x4E, 0x00, 0x01, 0x80, 0x80, 0xD4, 0xCF); - - z80_payload.add_bytes(2, asm_start.place_pointer(&z80_payload), 0x00); // These values must not have any control characters in them. - - z80_payload.add_bytes(33, - 0x4E, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4E, 0x50, 0x00, 0x00, - 0x00, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x59); - - // Mon #2 name - z80_payload.index = 0x16F; - for (int i = 0; i < 11; i++) - { - z80_payload.add_byte(0x4E); - } - - // Now that the ACE has been set up, we can use the space between Mon #2's data and Mon #2's name to put our code. - // Since this space is larger than the patchlist, we will be able to fit everything in it - - // Patchlist preamble - // At 0x1B4 0x07 in length - // Set as five 0xFD, the 0xFF will be added as part of the patch list. - for (int i = 0; i < 5; i++) - { - z80_patchlist.add_byte(0xFD); - } - - z80_payload.index = 0x72; - - array_counter.insert_variable(&z80_payload); - removal_array.insert_variable(&z80_payload); - transfer_wait_string.insert_variable(&z80_payload); - - asm_start.set_start(&z80_payload); - - z80_payload.CALL(0x2233 | T_U16); // Stop the battle music - - /* Write transferring message to screen: */ - // call ClearScreen - z80_payload.CALL(curr_rom.clearScreen | T_U16); - z80_payload.LD(HL, curr_rom.textBorderUppLeft | T_U16); - z80_payload.LD(C, curr_rom.textBorderWidth | T_U8); - z80_payload.LD(B, curr_rom.textBorderHeight | T_U8); - z80_payload.CALL(curr_rom.CableClub_TextBoxBorder | T_U16); - z80_payload.LD(HL, curr_rom.transferStringLocation | T_U16); - z80_payload.LD(DE, transfer_wait_string.place_ptr(&z80_payload) | T_U16); - z80_payload.CALL(curr_rom.placeString | T_U16); - z80_payload.JR(skip_enemy_write.place_relative_jump(&z80_payload) | T_I8); // This is a simple way to avoid the enemy name placement. Might have to modify for other languages - - z80_payload.index = 0xCA; - - skip_enemy_write.set_start(&z80_payload); - - // Reload the save data to remove any data that was overwritten during exploit entry - z80_payload.LD(B, (curr_rom.LoadCurrentBoxData >> 16) | T_U8); - z80_payload.LD(HL, curr_rom.LoadCurrentBoxData | T_U16); - z80_payload.CALL(curr_rom.Bankswitch | T_U16); - if (!debug) - { - /* Build the packet */ - // HL is the current data pointer - // DE is the destination pointer - // A is the checksum - // B is the 0xFE flag byte - // C is the counter - send_packet_loop.set_start(&z80_payload); - - z80_payload.LD(HL, (DATA_LOC + PACKET_SIZE + 3) | T_U16); // Load the next data location into HL - z80_payload.LD(A, HLI_PTR); - z80_payload.LD(H, HL_PTR); - z80_payload.LD(L, A); - z80_payload.LD(DE, (DATA_LOC + 2) | T_U16); // Enemy Pokemon data, should be unused - z80_payload.XOR(A, A); // Clear the register - z80_payload.LD(B, A); // Clear B as well - z80_payload.LD(C, A); // Clear C as well - z80_payload.PUSH(AF); - packet_loop.set_start(&z80_payload); - z80_payload.LD(B, 0x00 | T_U8); // Reset the flag byte - z80_payload.POP(AF); - z80_payload.ADD(A, HL_PTR); // Add the current data to the checksum - z80_payload.PUSH(AF); - z80_payload.LD(A, 0xFE); - z80_payload.CP(A, HL_PTR); // Compare the current data to 0xFE - z80_payload.LD(A, HLI_PTR); // Load HL's data into A for modification (if need be) - - // If HL's data is 0xFE - z80_payload.JR(NZ_F, fe_bypass.place_relative_jump(&z80_payload) | T_I8); - z80_payload.DEC(A); - z80_payload.INC(B); // Set flag - - fe_bypass.set_start(&z80_payload); - z80_payload.LD(DE_PTR, A); // Place the data in - z80_payload.INC(DE); - z80_payload.PUSH(AF); - z80_payload.LD(A, B); - z80_payload.LD(DE_PTR, A); // Place the flag in as well - z80_payload.POP(AF); - z80_payload.INC(DE); - z80_payload.INC(C); - z80_payload.LD(A, DATA_PER_PACKET - 1); - z80_payload.CP(A, C); - z80_payload.JR(NC_F, packet_loop.place_relative_jump(&z80_payload) | T_I8); // If all the data has been set, send the rest of the data - z80_payload.POP(AF); - z80_payload.RES(7 | T_BIT, A); // Reset bit 7 of the checksum, guaranteeing that it will never be 0xFE - z80_payload.LD(DE_PTR, A); - z80_payload.INC(DE); - z80_payload.LD(A, H); - - z80_payload.LD(DE_PTR, A); - z80_payload.INC(DE); - z80_payload.LD(A, L); - z80_payload.LD(DE_PTR, A); - - /* Transfer box data packet: */ - z80_payload.LD(A, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug - z80_payload.LDH((curr_rom.hSerialConnectionStatus & 0xFF) | T_U8, A); // Since hSerialConnectionStatus is at 0xFFxx we can use this method instead - z80_payload.LD(HL, DATA_LOC | T_U16); - z80_payload.LD(HL_PTR, 0xFD | T_U8); // set the start of the data to 0xFD so Serial_ExchangeBytes is happy - z80_payload.INC(HL); - z80_payload.LD(HL_PTR, 0x00 | T_U8); // add a 0x00 after the 0xFD to prevent further 0xFDs from being interpreted as part of the preamble - z80_payload.DEC(HL); // Reset HL back so it points to 0xFD - z80_payload.LD(DE, (DATA_LOC + PACKET_SIZE) | T_U16); // location to put stored data - z80_payload.LD(BC, PACKET_SIZE | T_U16); - if (debug) // Don't call serialExchangeBytes if debug is enabled - { - z80_payload.index += 3; - } - else - { - z80_payload.CALL(curr_rom.Serial_ExchangeBytes | T_U16); - } - - z80_payload.LD(A, (DATA_LOC + PACKET_SIZE + 3 + 1) | T_U16); - z80_payload.CP(A, 0xFF); - if (debug && false) // Don't compare the "recieved" data if in debug - { - z80_payload.index += 2; - } - else - { - z80_payload.JR(NZ_F, send_packet_loop.place_relative_jump(&z80_payload) | T_I8); - } - } - /* Recieve the Pokemon to remove */ - z80_payload.LD(HL, curr_rom.hSerialConnectionStatus | T_U16); // This can also be shortened - z80_payload.LD(HL_PTR, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug - z80_payload.LD(HL, curr_rom.garbageDataLocation | T_U16); - z80_payload.LD(DE, removal_array.place_ptr(&z80_payload) | T_U16); - z80_payload.LD(BC, 0x001E | T_U16); // Preamble does *not* count - if (debug) // Don't add in the Serial_ExchangeBytes call if in debug - { - z80_payload.index += 3; - } - else - { - z80_payload.CALL(curr_rom.Serial_ExchangeBytes | T_U16); - } - - /* Remove the transfered Pokemon */ - z80_payload.LD(HL, curr_rom.wRemoveMonFromBox | T_U16); - z80_payload.LD(HL_PTR, 0x01 | T_U8); // != 0x00 specifies the current box - remove_array_loop.set_start(&z80_payload); - z80_payload.LD(A, array_counter.place_ptr(&z80_payload) | T_U16); - z80_payload.LD(E, A); - z80_payload.LD(D, 0x00 | T_U8); - z80_payload.LD(HL, removal_array.place_ptr(&z80_payload) | T_U16); - z80_payload.ADD(HL, DE); - z80_payload.INC(A); - z80_payload.LD(array_counter.place_ptr(&z80_payload) | T_U16, A); - z80_payload.LD(A, curr_rom.wBoxCount | T_U16); - z80_payload.LD(B, A); - z80_payload.LD(A, HL_PTR); - z80_payload.CP(A, 0xFF | T_U8); - z80_payload.JR(Z_F, save_box.place_relative_jump(&z80_payload) | T_I8); - z80_payload.CP(A, B); - z80_payload.JR(NC_F, remove_array_loop.place_relative_jump(&z80_payload) | T_I8); - z80_payload.LD(HL, curr_rom.wWhichPokemon | T_U16); - z80_payload.LD(HL_PTR, A); - if (DONT_REMOVE_PKMN) - { - z80_payload.index += 3; - } - else - { - z80_payload.LD(B, (curr_rom._RemovePokemon >> 16) | T_U8); // Load ROM Bank - z80_payload.LD(HL, curr_rom._RemovePokemon | T_U16); - z80_payload.CALL(curr_rom.Bankswitch | T_U16); - } - z80_payload.JR((remove_array_loop.place_relative_jump(&z80_payload) & 0xFF) | T_I8); - - // We need to move this in order to not corrupt the 4E's - z80_payload.JR((save_box.place_relative_jump(&z80_payload) & 0xFF) | T_I8); - z80_payload.index = 0x17A; - - /* Save the current box */ - save_box.set_start(&z80_payload); - z80_payload.LD(B, (curr_rom.SaveSAVtoSRAM1 >> 16) | T_U8); // Load ROM Bank - z80_payload.LD(HL, curr_rom.SaveSAVtoSRAM1 | T_U16); - z80_payload.CALL(curr_rom.Bankswitch | T_U16); - z80_payload.CALL(curr_rom.SaveSAVtoSRAM2 | T_U16); // The bank is already loaded, we don't have to load it again - z80_payload.JP(curr_rom.SoftReset | T_U16); - - // z80_payload.index += 5; - - // Patchlist - // At 0x1BB / 0x1DE, 0xC2 in length (0xC4, but the last 2 are unused) - z80_patchlist.generate_patchlist(&z80_payload); - - // This payload works by placing Pokemon ID 0xFC's name in the stack, and causing a return to CD8E, - // which is part of the RNG seed. From there we can jump anywhere- and we choose to jump to D887, - // which is the rival's name. This code fixes the stack and jumps to the patchlist, which is where - // our final code is. - - // Update all the pointers - for (unsigned int i = 0; i < var_vector.size(); i++) - { - var_vector.at(i)->update_ptrs(); - } - for (unsigned int i = 0; i < jump_vector.size(); i++) - { - jump_vector.at(i)->update_jumps(); - } - - // Combine the vectors into the full payload - u8 *cur_out = payload_buffer; - memcpy(cur_out, z80_rng_seed.data_vector.data(), z80_rng_seed.data_vector.size()); - cur_out += z80_rng_seed.data_vector.size(); - memcpy(cur_out, z80_payload.data_vector.data(), z80_payload.data_vector.size()); - cur_out += z80_payload.data_vector.size(); - memcpy(cur_out, z80_patchlist.data_vector.data(), z80_patchlist.data_vector.size()); - cur_out += z80_patchlist.data_vector.size(); - - return; - - /* - else if (type == EVENT) - { - // ld a, $03 - payload_storage[offset++] = 0x3A; - payload_storage[offset++] = 0x03; - - // call OpenSRAM - payload_storage[offset++] = 0xC3; - payload_storage[offset++] = (curr_rom.OpenSRAM >> 0) & 0xFF; - payload_storage[offset++] = (curr_rom.OpenSRAM >> 8) & 0xFF; - - // ld de, $BEB0 - payload_storage[offset++] = 0x11; - payload_storage[offset++] = 0xB0; - payload_storage[offset++] = 0xBE; - - // ld bc, $150 - payload_storage[offset++] = 0x01; - payload_storage[offset++] = 0x50; - payload_storage[offset++] = 0x01; - - // ld hl, ??? - payload_storage[offset++] = 0x21; - payload_storage[offset++] = 0x00; - payload_storage[offset++] = 0x00; - - // CUSTOM EVENT SCRIPT: - // Start with the table data - int init_offset = offset; - insert_ext_copy_cmd(&offset, 0x11410E, 0xD930, 18); // Copy text pointers - insert_ext_copy_cmd(&offset, 0x00C120, 0xC140, 10); // - insert_ext_copy_cmd(&offset, 0x00C220, 0xC240, 16); // - byte temp[] = {0xD0, 0x0A}; - insert_int_copy_cmd(&offset, 0xD4E9, 2, temp); // - byte temp1[] = {0x15, 0x05}; - insert_int_copy_cmd(&offset, 0xD517, 2, temp1); // - byte temp2[] = {0x30, 0xD9}; - insert_int_copy_cmd(&offset, 0xD36B, 2, temp2); // - byte temp3[] = {0x0B, 0xF0, 0xFF}; - insert_int_copy_cmd(&offset, 0xD5D3, 3, temp3); // - byte temp4[] = {0x05}; - insert_int_copy_cmd(&offset, 0xD4E0, 1, temp4); // - byte temp5[] = {0x44, 0xD9, 0x08, 0x21, 0x54, 0xD9, 0xCD, 0x68, 0x31, 0x21, 0xB0, 0xC1, 0x00, 0x00, 0xC3, 0xD2, 0x23, 0x01, 0x00, 0x5E, 0xD8, 0xD8, 0xC9, 0xD8, 0xC9, 0xD8, 0xC9, 0xD8, 0xC9, 0x00, 0x8C, 0xB8, 0xB4, 0xB4, 0xE7, 0x50, 0x08, 0x3E, 0x83, 0xCD, 0x8B, 0x11, 0xCD, 0x3E, 0x37, 0xC3, 0xD2, 0x23}; - insert_int_copy_cmd(&offset, 0xD942, 48, temp5); // - payload_storage[offset++] = 0xFF; - - - // call CloseSRAM - payload_storage[offset++] = 0xC3; - payload_storage[offset++] = (curr_rom.CloseSRAM >> 0) & 0xFF; - payload_storage[offset++] = (curr_rom.CloseSRAM >> 8) & 0xFF; - - // call SoftReset - payload_storage[offset++] = 0xC3; - payload_storage[offset++] = (curr_rom.SoftReset >> 0) & 0xFF; - payload_storage[offset++] = (curr_rom.SoftReset >> 8) & 0xFF; - - }*/ - } - - else if (curr_rom.generation == 2) - { - std::vector jump_vector; - std::vector var_vector; - - z80_asm_handler z80_rng_seed(0x0A, curr_rom.wSerialOtherGameboyRandomNumberListBlock); - z80_asm_handler z80_payload(0x1CD, curr_rom.wSerialEnemyDataBlock); // wOTPartyData - z80_asm_handler z80_patchlist(0xC9, curr_rom.wSerialEnemyMonsPatchList); // wOTPatchLists - - /* - Initally the entire wLinkData is copied into the data section at D26B. - then, CopyBytes is called four times within link.skip_mail: - 1. It copies 0xB bytes from wLinkData to wOTPlayerName (D26B) - 2. It copies 0x8 bytes from where the previous one ended (D280) to wOTPartyCount - 3. It copies 0x2 bytes from where the previous one ended (D276) to wOTPlayerID - 4. It copies 0x1A4 bytes from where the previous one ended (D288) to wOTPartyMons - - 8 bytes aren't overwritten when copied over (D278-D28F), which is where the weird offset comes from. These bytes are index 0xE through 0x15 in the original data - By having 9 bytes of 0xFD, the offset ends up working out correctly. - */ - - z80_jump asm_start(&jump_vector); - z80_jump save_box(&jump_vector); - z80_jump remove_array_loop(&jump_vector); - z80_jump jump_to_party(&jump_vector); - z80_jump jump_to_payload(&jump_vector); - z80_jump packet_loop(&jump_vector); - z80_jump fe_bypass(&jump_vector); - z80_jump send_packet_loop(&jump_vector); - - z80_variable array_counter(&var_vector, 1, 0x00); // 1 byte to store the current array counter - z80_variable removal_array(&var_vector); // 40 byte storage for list of Pokemon to remove, plus a permanent array terminator - byte removal_array_data[41]; - for (int i = 0; i < 41; i++) - { - if (debug) - { - removal_array_data[i] = (i < 30 ? (29 - i) : 0xFF); - } - else - { - removal_array_data[i] = (i < 30 ? 0xFD : 0xFF); - } - } - removal_array.load_data(41, removal_array_data); - z80_variable transfer_wait_string(&var_vector, 13, // SENDING DATA - 0x92, 0x84, 0x8D, 0x83, 0x88, 0x8D, 0x86, 0x7F, 0x83, 0x80, 0x93, 0x80, 0x50); - z80_variable custom_name(&var_vector, 11, // FENNEL - 0x85, 0x84, 0x8D, 0x8D, 0x84, 0x8B, 0x50, 0x50, 0x50, 0x50, 0x50); - - // RNG Seed: - // at 0x00, 0x0A in length - // Does not need to be set - - // Preamble - // At 0x00, 0x09 in length - // Must be filled with 0xFD - for (int i = 0; i < 9; i++) - { - z80_payload.add_byte(0xFD); - } - - // Preamble/Rival name - // At 0x00, 0x1C5 in length - // Set to stored name - int distance = curr_rom.stack_overwrite_location - curr_rom.print_string_start; - int remainder = distance % 40; - distance /= 40; // Automatically truncated, so it won't overshoot - distance -= 8; // There will be 8 extra bytes due to how the copy functions work. - - for (int i = 0; i < distance; i++) - { - z80_payload.add_byte(curr_rom.short_pkmn_name); - } - for (int i = 0; i < remainder; i++) - { - z80_payload.add_byte(0x80); - } - - z80_payload.index -= 1; // Prep for the direct jump, since it usually has to jump forward one for the ASM call - jump_to_payload.place_direct_jump(&z80_payload); - z80_payload.index += 3; - z80_payload.add_byte(0x50); // String terminator - - // Saving the box overwrites our code, so we need to move it here. - jump_to_party.set_start(&z80_payload); - z80_payload.LD(A, curr_rom.SaveBox >> 16 | T_U8); - z80_payload.RST(0x10); // Bank switch - z80_payload.CALL(curr_rom.SaveBox | T_U16); - - z80_payload.JP(curr_rom.SoftReset | T_U16); - - // Patchlist preamble - // At 0x1B4 / 0x1D7, 0x07 in length - // Set as five 0xFD and two 0xFF - - for (int i = 0; i < 7; i++) - { - z80_patchlist.add_byte(i < 5 ? 0xFD : 0xFF); - } - - // Patchlist - // At 0x1DE, 194 in length - // Fill with custom code - - // Write transferring message to screen: - // call ClearScreen - jump_to_payload.set_start(&z80_patchlist); - z80_patchlist.CALL(curr_rom.clearScreen | T_U16); - - z80_patchlist.LD(HL, curr_rom.textBorderUppLeft | T_U16); - z80_patchlist.LD(C, curr_rom.textBorderWidth | T_U8); - z80_patchlist.LD(B, curr_rom.textBorderHeight | T_U8); - z80_patchlist.LD(A, curr_rom.CableClub_TextBoxBorder >> 16 | T_U8); - z80_patchlist.RST(0x10); // Bank switch - z80_patchlist.CALL(curr_rom.CableClub_TextBoxBorder | T_U16); - z80_patchlist.LD(HL, curr_rom.transferStringLocation | T_U16); - z80_patchlist.LD(DE, transfer_wait_string.place_ptr(&z80_patchlist) | T_U16); - - // call PlaceString - z80_patchlist.CALL(curr_rom.placeString | T_U16); - - // call OpenSRAM - z80_patchlist.LD(A, 0x01 | T_U8); - z80_patchlist.CALL(curr_rom.OpenSRAM | T_U16); - - /* Build the packet */ - // HL is the current data pointer - // DE is the destination pointer - // A is the checksum - // B is the 0xFE flag byte - // C is the counter - send_packet_loop.set_start(&z80_patchlist); - - z80_patchlist.LD(HL, (DATA_LOC + PACKET_SIZE + 3) | T_U16); // Load the next data location into HL - z80_patchlist.LD(A, HLI_PTR); - z80_patchlist.LD(H, HL_PTR); - z80_patchlist.LD(L, A); - - z80_patchlist.LD(DE, (DATA_LOC + 2) | T_U16); // Enemy Pokemon data, should be unused - z80_patchlist.XOR(A, A); // Clear the register - z80_patchlist.LD(B, A); // Clear B as well - z80_patchlist.LD(C, A); // Clear C as well - z80_patchlist.PUSH(AF); - packet_loop.set_start(&z80_patchlist); - z80_patchlist.LD(B, 0x00 | T_U8); // Reset the flag byte - z80_patchlist.POP(AF); - z80_patchlist.ADD(A, HL_PTR); // Add the current data to the checksum - z80_patchlist.PUSH(AF); - z80_patchlist.LD(A, 0xFE); - z80_patchlist.CP(A, HL_PTR); // Compare the current data to 0xFE - z80_patchlist.LD(A, HLI_PTR); // Load HL's data into A for modification (if need be) - - // If HL's data is 0xFE - z80_patchlist.JR(NZ_F, fe_bypass.place_relative_jump(&z80_patchlist) | T_I8); - z80_patchlist.DEC(A); - z80_patchlist.INC(B); // Set flag - - fe_bypass.set_start(&z80_patchlist); - z80_patchlist.LD(DE_PTR, A); // Place the data in - z80_patchlist.INC(DE); - z80_patchlist.PUSH(AF); - z80_patchlist.LD(A, B); - z80_patchlist.LD(DE_PTR, A); // Place the flag in as well - z80_patchlist.POP(AF); - z80_patchlist.INC(DE); - z80_patchlist.INC(C); - z80_patchlist.LD(A, DATA_PER_PACKET - 1); - z80_patchlist.CP(A, C); - z80_patchlist.JR(NC_F, packet_loop.place_relative_jump(&z80_patchlist) | T_I8); // If all the data has been set, send the rest of the data - z80_patchlist.POP(AF); - z80_patchlist.RES(7 | T_BIT, A); // Reset bit 7 of the checksum, guaranteeing that it will never be 0xFE - z80_patchlist.LD(DE_PTR, A); - z80_patchlist.INC(DE); - z80_patchlist.LD(A, H); - z80_patchlist.LD(DE_PTR, A); - z80_patchlist.INC(DE); - z80_patchlist.LD(A, L); - z80_patchlist.LD(DE_PTR, A); - - /* Transfer box data packet: */ - z80_patchlist.LD(A, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug - z80_patchlist.LDH((curr_rom.hSerialConnectionStatus & 0xFF) | T_U8, A); // Since hSerialConnectionStatus is at 0xFFxx we can use this method instead - z80_patchlist.LD(HL, DATA_LOC | T_U16); - z80_patchlist.LD(HL_PTR, 0xFD | T_U8); // set the start of the data to 0xFD so Serial_ExchangeBytes is happy - z80_patchlist.INC(HL); - z80_patchlist.LD(HL_PTR, 0x00 | T_U8); // add a 0x00 after the 0xFD to prevent further 0xFDs from being interpreted as part of the preamble - z80_patchlist.DEC(HL); // Reset HL back so it points to 0xFD - z80_patchlist.LD(DE, (DATA_LOC + PACKET_SIZE) | T_U16); // location to put stored data - z80_patchlist.LD(BC, PACKET_SIZE | T_U16); - if (debug) // Don't call serialExchangeBytes if debug is enabled - { - z80_patchlist.index += 3; - } - else - { - z80_patchlist.CALL(curr_rom.Serial_ExchangeBytes | T_U16); - } - - z80_patchlist.LD(A, (DATA_LOC + PACKET_SIZE + 3 + 1) | T_U16); - z80_patchlist.CP(A, 0xFF); - z80_patchlist.JR(NZ_F, send_packet_loop.place_relative_jump(&z80_patchlist) | T_I8); - - // Recieve the Pokemon to remove - z80_patchlist.LD(HL, curr_rom.hSerialConnectionStatus | T_U16); // This can also be shortened - z80_patchlist.LD(HL_PTR, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug - z80_patchlist.LD(HL, curr_rom.garbageDataLocation | T_U16); - z80_patchlist.LD(DE, removal_array.place_ptr(&z80_patchlist) | T_U16); - z80_patchlist.LD(BC, 0x001E | T_U16); // Preamble does *not* count - if (debug) // Don't add in the Serial_ExchangeBytes call if in debug - { - z80_patchlist.index += 3; - } - else - { - z80_patchlist.CALL(curr_rom.Serial_ExchangeBytes | T_U16); - } - - // Remove the transfered Pokemon - z80_patchlist.LD(HL, curr_rom.wRemoveMonFromBox | T_U16); - z80_patchlist.LD(HL_PTR, 0x01 | T_U8); // != 0x00 specifies the current box - remove_array_loop.set_start(&z80_patchlist); - z80_patchlist.LD(A, array_counter.place_ptr(&z80_patchlist) | T_U16); - z80_patchlist.LD(E, A); - z80_patchlist.LD(D, 0x00 | T_U8); - z80_patchlist.LD(HL, removal_array.place_ptr(&z80_patchlist) | T_U16); - z80_patchlist.ADD(HL, DE); - z80_patchlist.INC(A); - z80_patchlist.LD(array_counter.place_ptr(&z80_patchlist) | T_U16, A); - z80_patchlist.LD(A, curr_rom.wBoxCount | T_U16); - z80_patchlist.LD(B, A); - z80_patchlist.LD(A, HL_PTR); - z80_patchlist.CP(A, 0xFF | T_U8); - z80_patchlist.JR(Z_F, save_box.place_relative_jump(&z80_patchlist) | T_I8); - z80_patchlist.CP(A, B); - z80_patchlist.JR(NC_F, remove_array_loop.place_relative_jump(&z80_patchlist) | T_I8); - z80_patchlist.LD(HL, curr_rom.wWhichPokemon | T_U16); - z80_patchlist.LD(HL_PTR, A); - if (DONT_REMOVE_PKMN) - { - z80_patchlist.index += 6; - } - else - { - z80_patchlist.LD(A, curr_rom._RemovePokemon >> 16 | T_U8); - z80_patchlist.RST(0x10); // Bank switch - z80_patchlist.CALL(curr_rom._RemovePokemon | T_U16); - } - z80_patchlist.JR(remove_array_loop.place_relative_jump(&z80_patchlist) | T_I8); - - save_box.set_start(&z80_patchlist); - z80_patchlist.JP(jump_to_party.place_direct_jump(&z80_patchlist) | T_U16); // jp pkmn list (because saving the box overwrites the data) - - array_counter.insert_variable(&z80_patchlist); - removal_array.insert_variable(&z80_payload); - transfer_wait_string.insert_variable(&z80_patchlist); - - // This payload works by placing Pokemon ID 0xFC's name in the stack, and causing a return to CD8E, - // which is part of the RNG seed. From there we can jump anywhere- and we choose to jump to D887, - // which is the rival's name. This code fixes the stack and jumps to the patchlist, which is where - // our final code is. - - // Update all the pointers - for (unsigned int i = 0; i < var_vector.size(); i++) - { - var_vector.at(i)->update_ptrs(); - } - for (unsigned int i = 0; i < jump_vector.size(); i++) - { - jump_vector.at(i)->update_jumps(); - } - - // Combine the vectors into the full payload - u8 *cur_out = payload_buffer; - memcpy(cur_out, z80_rng_seed.data_vector.data(), z80_rng_seed.data_vector.size()); - cur_out += z80_rng_seed.data_vector.size(); - memcpy(cur_out, z80_payload.data_vector.data(), z80_payload.data_vector.size()); - cur_out += z80_payload.data_vector.size(); - memcpy(cur_out, z80_patchlist.data_vector.data(), z80_patchlist.data_vector.size()); - cur_out += z80_patchlist.data_vector.size(); - - return; - - // This payload works by placing Pokemon ID 0xFC's name in the stack, and causing a return to CD8E, - // which is part of the RNG seed. From there we can jump anywhere- and we choose to jump to D887, - // which is the rival's name. This code fixes the stack and jumps to the patchlist, which is where - // our final code is. - } - memset(payload_buffer, 0x00, PAYLOAD_SIZE); -}; - -#if PAYLOAD_EXPORT_TEST -#include -#include "gb_rom_values/gb_rom_values.h" -int main() // Rename to "main" to send the payload to test_payload.txt -{ - byte buffer[672] = {0}; - freopen("test_payload.txt", "w", stdout); - printf("\n"); - init_payload(buffer, gb_rom_values_eng[RED_ID], TRANSFER, true); - - if (true) - { - for (int i = 0; i < 0x2A0; i++) - { - printf("0x%02X, ", (unsigned int)buffer[i]); - if (i % 0x10 == 0xF) - { - printf("\n# 0x%X\n", i + 1); - } - } - return 0; - } - else - { - for (int i = 0; i < 0x150; i++) - { - printf("%02X ", (unsigned int)buffer[i + ((0x10 * 28) + 9)]); - if (i % 0x10 == 0xF) - { - printf("\n"); - } - } - return 0; - } -} -#endif \ No newline at end of file diff --git a/source/custom_malloc.cpp b/source/custom_malloc.cpp index e521f8c..2c5079a 100644 --- a/source/custom_malloc.cpp +++ b/source/custom_malloc.cpp @@ -201,6 +201,9 @@ void malloc_init_default_pool(void) memset(g_alloc_map, 0, sizeof(g_alloc_map)); // Clear bitmap } +extern "C" +{ + /// @brief The custom implementation of the bitmap allocator described at the top of this module. void* malloc(size_t size) { @@ -333,6 +336,8 @@ void _free_r(struct _reent *r, void* ptr) { return free(ptr); } +} + #else void malloc_init_default_pool(void)