diff --git a/README.md b/README.md index c461478..974dbe6 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Pokémon Transfered using Poké Transporter GB *will* be removed from Red, Blue, Currently the only release is in English. Releases supporting other languages is planned for the near future. -Only English copies of Red, Blue, Yellow, Gold, Silver, Crystal, Ruby, Sapphire, FireRed, LeafGreen, and Emerald are supported at this time. Compatibility for other languages will be added in the near future. +Currently English versions of Red, Blue, Yellow, Gold, Silver, Crystal are supported- plus English, Spanish, German, Italian, French versions of Ruby, Sapphire, FireRed, LeafGreen, and Emerald. Compatibility for other languages is currently in development and will be added in the near future. ## Usage Poké Transporter GB is a Multiboot program for the Game Boy Advance. There are two main ways to run the Poké Transporter GB ROM on a Game Boy Advance: @@ -52,7 +52,7 @@ A full list of modifications made to transfered Pokémon can be found [here](htt A video showcasing Poké Transporter GB can be found [here](https://www.youtube.com/watch?v=47A6p2hH2gU), and a video detailing some of the development process can be found [here](https://youtu.be/9mSkGhEYBkg)! ## Why? -One of my favorite aspects of the Pokémon franchise is the ability to send Pokémon forward into the most recent generation. Of course, this isn't possible from the Gameboy games into the Gameboy Advance era- and I wanted to fix that. A handful of Poeople have bridged the gap before, but Poké Transporter GB is the first tool designed to transfer Pokémon like the Pal Park, PokéTransport Lab, and PokéTransporter for Generation 1 and 2 to Generation 3. Documentation detailing the design process of Poké Transporter GB can be found [here](https://www.austinthomasweber.com/poke-transporter-gb)! +One of my favorite aspects of the Pokémon franchise is the ability to send Pokémon forward into the most recent generation. Of course, this isn't possible from the Gameboy games into the Gameboy Advance era- and I wanted to fix that. A handful of people have bridged the gap before, but Poké Transporter GB is the first tool designed to transfer Pokémon like the Pal Park, PokéTransport Lab, and PokéTransporter for Generation 1 and 2 to Generation 3. Documentation detailing the design process of Poké Transporter GB can be found [here](https://www.austinthomasweber.com/poke-transporter-gb)! # Credits ## Inspired by the works of: @@ -121,4 +121,4 @@ Everything else, and the programming code, is governed by the MIT license _This project is not endorsed or supported by GameFreak or Nintendo. Please support the original developers._ ## Special Mentions -A huge thank you to Goppier for being the first one to bridge the gap between generation 2 and generation 3 and for provide extremely useful documentation about both versions of the Link Cable, and a huge thank you to Lorenzooone for being the direct inspiration for this project, as well as answering questions I had during development. This project would never have happened without either of them, and I cannot thank them enough. +A huge thank you to Goppier for being the first one to bridge the gap between generation 2 and generation 3 and for providing extremely useful documentation about both versions of the Link Cable, and a huge thank you to Lorenzooone for being the direct inspiration for this project, as well as answering questions I had during development. This project would never have happened without either of them, and I cannot thank them enough. diff --git a/include/debug_mode.h b/include/debug_mode.h index 96eff81..d7d8ee8 100644 --- a/include/debug_mode.h +++ b/include/debug_mode.h @@ -1,20 +1,23 @@ #ifndef DEBUG_MODE_H #define DEBUG_MODE_H -#define VERSION "v1.1.4 D" +#define VERSION "v1.1.1" +#define PTGB_BUILD_LANGUAGE ENG_ID -#define DEBUG_MODE false // This is currently broken... not sure why -#define INSTANT_TEXT_SPEED true -#define IGNORE_GAME_PAK true -#define IGNORE_LINK_CABLE false -#define IGNORE_MG_E4_FLAGS true -#define IGNORE_UNRECEIVED_PKMN true -#define FORCE_TUTORIAL false -#define DONT_REMOVE_PKMN true -#define NO_INVALID_PKMN false -#define IGNORE_DEX_COMPLETION false -#define WRITE_CABLE_DATA_TO_SAVE true -#define SHOW_DATA_PACKETS true +#define DEBUG_MODE false + +#define PRINT_LINK_DATA (false && DEBUG_MODE) // This is currently broken... not sure why +#define INSTANT_TEXT_SPEED (true && DEBUG_MODE) +#define IGNORE_GAME_PAK (true && DEBUG_MODE) +#define IGNORE_LINK_CABLE (false && DEBUG_MODE) +#define IGNORE_MG_E4_FLAGS (true && DEBUG_MODE) +#define IGNORE_UNRECEIVED_PKMN (true && DEBUG_MODE) +#define FORCE_TUTORIAL (false && DEBUG_MODE) +#define DONT_REMOVE_PKMN (true && DEBUG_MODE) +#define NO_INVALID_PKMN (false && DEBUG_MODE) +#define IGNORE_DEX_COMPLETION (false && DEBUG_MODE) +#define WRITE_CABLE_DATA_TO_SAVE (true && DEBUG_MODE) +#define SHOW_DATA_PACKETS (true && DEBUG_MODE) #define DEBUG_GAME EMERALD_ID #define DEBUG_VERS VERS_1_0 diff --git a/source/gameboy_colour.cpp b/source/gameboy_colour.cpp index d6c9b80..8f4a761 100644 --- a/source/gameboy_colour.cpp +++ b/source/gameboy_colour.cpp @@ -122,12 +122,6 @@ void setup() init_packet = true; end_of_data = false; - if (DEBUG_MODE && false) - { - tte_erase_rect(LEFT, TOP, RIGHT, BOTTOM); - tte_set_pos(0, 0); - tte_write("FEED ME POKEMON, I HUNGER!\n"); - } set_textbox_large(); tte_erase_screen(); tte_set_pos(40, 24); @@ -184,7 +178,7 @@ byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_ { tte_erase_screen(); tte_set_pos(40, 24); - tte_write("\n\n\nLink was successful!\n\n Waiting for trade"); + tte_write(curr_gb_rom->version != YELLOW_ID ? "\n\n\nLink was successful!\n\n Waiting for trade" : "\n\n\nLink was successful!\n\n Waiting for battle"); link_animation_state(STATE_NO_ANIM); state = pretrade; data_counter = 0; @@ -317,7 +311,7 @@ int loop(byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, Simpli // TODO: Restore Errors in_data = linkSPI->transfer(out_data); - if (DEBUG_MODE && false) + if (PRINT_LINK_DATA && false) { tte_set_margins(0, 0, H_MAX, V_MAX); print( @@ -353,7 +347,7 @@ int loop(byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, Simpli return 0; } - if (DEBUG_MODE && key_hit(KEY_SELECT)) + if (key_held(KEY_SELECT)) // Forces a disconnect... not sure why it would need to be locked behind debug mode { return COND_ERROR_DISCONNECT; } @@ -405,9 +399,9 @@ byte exchange_boxes(byte curr_in, byte *box_data_storage, GB_ROM *curr_gb_rom) } if (SHOW_DATA_PACKETS) { - tte_write("P: "); - tte_write(std::to_string(data_packet[0]).c_str()); - tte_write("\n"); + tte_write("P: "); + tte_write(std::to_string(data_packet[0]).c_str()); + tte_write("\n"); for (int i = 0; i < DATA_PER_PACKET; i++) { tte_write(std::to_string(i).c_str()); @@ -475,6 +469,10 @@ byte exchange_boxes(byte curr_in, byte *box_data_storage, GB_ROM *curr_gb_rom) next_offset += DATA_PER_PACKET; } } + if (((next_offset + curr_gb_rom->wBoxDataStart) & 0xFF) == 0xFE) + { + next_offset -= 1; // Set back the offset if the byte sent would be 0xFE, since that would break the system + } if (SHOW_DATA_PACKETS) { diff --git a/source/payload_builder.cpp b/source/payload_builder.cpp index 59edb86..1ffc79d 100644 --- a/source/payload_builder.cpp +++ b/source/payload_builder.cpp @@ -443,9 +443,9 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug) 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.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 @@ -796,21 +796,18 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug) // C is the counter send_packet_loop.set_start(&z80_patchlist); - // Theoretically this could be changed to just take the direct address instead of adding the offset to it, if space is needed - z80_patchlist.LD(HL, (DATA_LOC + PACKET_SIZE + 3) | T_U16); - z80_patchlist.LD(E, HL_PTR); - z80_patchlist.INC(HL); - z80_patchlist.LD(D, HL_PTR); - z80_patchlist.LD(HL, curr_rom.wBoxDataStart | T_U16); - z80_patchlist.ADD(HL, DE); + 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 + 1) | T_U16); // Enemy Pokemon data, should be unused + 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.SLA(B); // Shift flag over + 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); @@ -822,18 +819,21 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug) 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); + 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, 0x07); + 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); + 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.LD(DE_PTR, A); - z80_patchlist.INC(DE); - z80_patchlist.LD(A, B); + 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); @@ -843,12 +843,13 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug) z80_patchlist.LD(DE_PTR, A); /* Transfer box data packet: */ - z80_patchlist.LD(HL, curr_rom.hSerialConnectionStatus | T_U16); // Can be shortened since it is 0xFFxx - z80_patchlist.LD(HL_PTR, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug + 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, 0xFF | T_U8); // add a value after the 0xFD to prevent further 0xFDs from being interpreted as part of the preamble + 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 @@ -956,7 +957,7 @@ int test_main() // Rename to "main" to send the payload to test_payload.txt { freopen("test_payload.txt", "w", stdout); std::cout << std::endl; - byte *payload = generate_payload(ENG_YELLOW, TRANSFER, true); + byte *payload = generate_payload(ENG_GOLD, TRANSFER, true); if (true) { for (int i = 0; i < 0x2A0; i++) diff --git a/source/script_array.cpp b/source/script_array.cpp index fab4602..d91b9c4 100644 --- a/source/script_array.cpp +++ b/source/script_array.cpp @@ -360,7 +360,7 @@ bool run_conditional(int index) for (int i = 0; i <= (8 * 7); i += 2) { REG_BG1HOFS = i + FENNEL_SHIFT; - if (!DEBUG_MODE) + if (!INSTANT_TEXT_SPEED) { global_next_frame(); } @@ -371,7 +371,7 @@ bool run_conditional(int index) for (int i = (8 * 7); i >= 0; i -= 2) { REG_BG1HOFS = i + FENNEL_SHIFT; - if (!DEBUG_MODE) + if (!INSTANT_TEXT_SPEED) { global_next_frame(); } diff --git a/source/text_engine.cpp b/source/text_engine.cpp index 416a119..32ebbe4 100644 --- a/source/text_engine.cpp +++ b/source/text_engine.cpp @@ -58,7 +58,7 @@ int text_loop(int script) { if (get_frame_count() % 2 == 0 || key_held(KEY_B) || key_held(KEY_A)) { - if (DEBUG_MODE) + if (INSTANT_TEXT_SPEED) { while (char_index < curr_text.length() && curr_text.substr(char_index, 1) != "|") {