Adding data packets to Red/Blue

This commit is contained in:
The Gears of Progress
2024-10-30 14:56:44 -04:00
parent 9d3221ae8d
commit cd2a9971a5
9 changed files with 272 additions and 67 deletions

View File

@@ -3,16 +3,17 @@
#define VERSION "v1.0.3 D"
#define DEBUG_MODE false
#define DEBUG_MODE true // This is currently broken... not sure why
#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 false
#define DONT_REMOVE_PKMN true
#define SHOW_INVALID_PKMN false
#define IGNORE_DEX_COMPLETION false
#define WRITE_CABLE_DATA_TO_SAVE true
#define SHOW_DATA_PACKETS false
#define DEBUG_GAME EMERALD_ID
#define DEBUG_VERS VERS_1_0

View File

@@ -35,7 +35,7 @@ void setup();
byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, Simplified_Pokemon *curr_simple_array, bool cancel_connection);
int loop(byte *box_data_storage, byte *curr_payload, GB_ROM *curr_rom, Simplified_Pokemon *curr_simple_array, bool cancel_connection);
byte exchange_parties(byte curr_in, byte *curr_payload);
byte exchange_boxes(byte curr_in, byte *party_data);
byte exchange_boxes(byte curr_in, byte *party_data, GB_ROM *curr_gb_rom);
byte exchange_remove_array(byte curr_in, Simplified_Pokemon *curr_simple_array, bool cancel_connection);
#endif /* GAMEBOY_COLOUR_H_ */

View File

@@ -58,10 +58,10 @@ const struct GB_ROM ENG_RED = {
.wSerialEnemyDataBlock = 0xD893,
.wSerialEnemyMonsPatchList = 0xC5D0,
.transferStringLocation = 0xC443,
.textBorderUppLeft = 0xC42E,
.textBorderWidth = 3,
.textBorderHeight = 14,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
};
const struct GB_ROM ENG_BLUE = {
.language = ENG_ID,
@@ -97,10 +97,10 @@ const struct GB_ROM ENG_BLUE = {
.wSerialEnemyDataBlock = 0xD893,
.wSerialEnemyMonsPatchList = 0xC5D0,
.transferStringLocation = 0xC443,
.textBorderUppLeft = 0xC42E,
.textBorderWidth = 3,
.textBorderHeight = 14,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
};
const struct GB_ROM ENG_YELLOW = {
.language = ENG_ID,
@@ -137,10 +137,10 @@ const struct GB_ROM ENG_YELLOW = {
.wSerialEnemyDataBlock = 0xD893,
.wSerialEnemyMonsPatchList = 0xC5D0,
.transferStringLocation = 0xC443,
.textBorderUppLeft = 0xC42E,
.textBorderWidth = 3,
.textBorderHeight = 14,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
};
const struct GB_ROM ENG_GOLD = {
.language = ENG_ID,
@@ -174,10 +174,10 @@ const struct GB_ROM ENG_GOLD = {
.wSerialEnemyDataBlock = 0xDD40, // wOTPartyData
.wSerialEnemyMonsPatchList = 0xC5D0, // wOTPatchLists
.transferStringLocation = 0xC443,
.textBorderUppLeft = 0xC42E,
.textBorderWidth = 3,
.textBorderHeight = 14,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
};
const struct GB_ROM ENG_SILVER = {
.language = ENG_ID,
@@ -211,10 +211,10 @@ const struct GB_ROM ENG_SILVER = {
.wSerialEnemyDataBlock = 0xDD40, // wOTPartyData
.wSerialEnemyMonsPatchList = 0xC5D0, // wOTPatchLists
.transferStringLocation = 0xC443,
.textBorderUppLeft = 0xC42E,
.textBorderWidth = 3,
.textBorderHeight = 14,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
};
const struct GB_ROM ENG_CRYSTAL = {
.language = ENG_ID,
@@ -248,10 +248,10 @@ const struct GB_ROM ENG_CRYSTAL = {
.wSerialEnemyDataBlock = 0xD26B, // wOTPartyData
.wSerialEnemyMonsPatchList = 0xC6D0, // wOTPatchLists
.transferStringLocation = 0xC543,
.textBorderUppLeft = 0xC52E,
.textBorderWidth = 3,
.textBorderHeight = 14,
.transferStringLocation = 0xC544,
.textBorderUppLeft = 0xC52F,
.textBorderWidth = 12,
.textBorderHeight = 1,
};
#endif

View File

@@ -35,9 +35,9 @@ public:
int nature_mod = 0;
int unown_letter = -1;
Pokemon();
void load_data(int index, byte *party_data, int game, int lang);
void load_data(int index, const byte *party_data, int game, int lang);
void convert_to_gen_three(bool simplified, bool stabilize_mythical);
void copy_from_to(byte *source, byte *destination, int size, bool reverse_endian);
void copy_from_to(const byte *source, byte *destination, int size, bool reverse_endian);
void alocate_data_chunks(byte *G, byte *A, byte *E, byte *M);
void insert_data(byte *first, byte *second, byte *third, byte *fourth);
byte get_gen_3_data(int index);

View File

@@ -59,6 +59,16 @@ int zero_count;
int state;
int mosi_delay = 4; // inital delay, speeds up once sending PKMN
int received_offset = 0;
int next_offset = 0;
int packet_index = 0;
bool failed_packet;
bool init_packet;
bool test_packet_fail = false;
byte data_packet[13];
std::string spi_text_out_array[10];
@@ -103,8 +113,14 @@ void setup()
FF_count = 0;
zero_count = 0;
next_offset = 0;
received_offset = 0;
packet_index = 0;
if (DEBUG_MODE)
failed_packet = false;
init_packet = true;
if (DEBUG_MODE && false)
{
tte_erase_rect(LEFT, TOP, RIGHT, BOTTOM);
tte_set_pos(0, 0);
@@ -225,6 +241,7 @@ byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_
if (in == 0xFD)
{
state = box_preamble;
init_packet = true;
}
else if ((curr_gb_rom->method == METHOD_MEW) && (in == 0xFE))
{
@@ -248,19 +265,14 @@ byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_
if (in != 0xFD)
{
state = box_data;
data_counter = 0;
return exchange_boxes(in, box_data_storage);
return exchange_boxes(in, box_data_storage, curr_gb_rom);
}
return in;
}
else if (state == box_data)
{
if (data_counter >= curr_gb_rom->box_data_size)
{
state = end1;
}
return exchange_boxes(in, box_data_storage);
return exchange_boxes(in, box_data_storage, curr_gb_rom);
}
else if (state == wait_to_resend)
@@ -326,7 +338,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)
if (DEBUG_MODE && false)
{
tte_set_margins(0, 0, H_MAX, V_MAX);
print(
@@ -388,11 +400,113 @@ byte exchange_parties(byte curr_in, byte *curr_payload)
return ret;
};
byte exchange_boxes(byte curr_in, byte *box_data_storage)
byte exchange_boxes(byte curr_in, byte *box_data_storage, GB_ROM *curr_gb_rom)
{
box_data_storage[data_counter] = curr_in;
data_counter += 1;
return curr_in;
if (SHOW_DATA_PACKETS)
{
tte_erase_rect(0, 0, H_MAX, V_MAX);
tte_set_pos(8, 8);
}
data_packet[packet_index] = curr_in;
if (packet_index == 12)
{
byte checksum = 0;
for (int i = 0; i < 8; i++)
{
if (((data_packet[10] >> (7 - i)) & 0x1) == 1)
data_packet[i + 1] = 0xFE;
{
checksum += data_packet[i + 1];
}
}
if (!init_packet)
{
received_offset = (data_packet[12] | (data_packet[11] << 8)) - (curr_gb_rom->wBoxDataStart + 8);
}
if (SHOW_DATA_PACKETS)
{
for (int i = 0; i < 13; i++)
{
tte_write(std::to_string(i).c_str());
tte_write(": ");
tte_write(std::to_string(data_packet[i]).c_str());
tte_write("\n");
}
tte_write(std::to_string(checksum).c_str());
tte_write(" = ");
tte_write(std::to_string(data_packet[9]).c_str());
}
if (checksum == data_packet[9] && !init_packet && !(test_packet_fail && received_offset == 128)) // Verify if the data matches the checksum
{
for (int i = 0; i < 8; i++)
{
if (received_offset + i <= curr_gb_rom->box_data_size)
{
box_data_storage[received_offset + i] = data_packet[i + 1];
}
}
}
else if (!init_packet)
{
failed_packet = true;
if (test_packet_fail)
{
test_packet_fail = false;
}
}
state = (received_offset > curr_gb_rom->box_data_size + 8 ? end1 : box_preamble);
if (SHOW_DATA_PACKETS)
{
tte_write("\nNO: ");
tte_write(std::to_string(next_offset).c_str());
tte_write("\nFP: ");
tte_write(std::to_string(failed_packet).c_str());
}
if (!init_packet)
{
if (failed_packet)
{
next_offset -= 8;
failed_packet = false;
}
else
{
next_offset += 8;
}
}
if (SHOW_DATA_PACKETS)
{
tte_write("\nRO: ");
tte_write(std::to_string(received_offset).c_str());
tte_write("\nIP: ");
tte_write(std::to_string(init_packet).c_str());
while (!key_held(KEY_A))
{
global_next_frame();
}
global_next_frame();
}
packet_index = 0;
init_packet = false;
}
packet_index += 1;
switch (packet_index)
{
case 3:
if (received_offset > 0x462)
{
return 0xFF;
}
return next_offset >> 8;
case 2:
return (next_offset >> 0);
default:
return 0;
}
};
byte exchange_remove_array(byte curr_in, Simplified_Pokemon *curr_simple_array, bool cancel_connection)

View File

@@ -8,6 +8,9 @@
#include <fstream>
#include <iomanip>
#define DATA_LOC 0xCFD8 // 0xC454
#define PACKET_SIZE (1 + 8 + 1 + 1 + 2) // 0xFD, 8 data bytes, the checksum, the flag bytes, and two location bytes
byte out_array[PAYLOAD_SIZE] = {};
byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
@@ -33,9 +36,13 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
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++)
{
@@ -49,10 +56,8 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
}
}
removal_array.load_data(41, removal_array_data);
z80_variable transfer_wait_string(&var_vector, 30, // TRANSFERRING..\n
// PLEASE WAIT!
0x93, 0x91, 0x80, 0x8D, 0x92, 0x85, 0x84, 0x91, 0x91, 0x88, 0x8D, 0x86, 0xF2, 0xF2, 0x4E,
0x7F, 0x8F, 0x8B, 0x84, 0x80, 0x92, 0x84, 0x7F, 0x96, 0x80, 0x88, 0x93, 0xE7, 0x7F, 0x50);
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);
@@ -114,20 +119,76 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
// call ClearScreen
z80_patchlist.CALL(curr_rom.clearScreen | T_U16);
z80_patchlist.LD(HL, curr_rom.textBorderUppLeft | T_U16);
z80_patchlist.LD(B, curr_rom.textBorderWidth | T_U8);
z80_patchlist.LD(C, curr_rom.textBorderHeight | T_U8);
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);
/* Transfer box data: */
/* 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);
// 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(DE, (DATA_LOC + 1) | 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.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);
z80_patchlist.INC(DE);
z80_patchlist.INC(C);
z80_patchlist.LD(A, 0x07);
z80_patchlist.CP(A, C);
z80_patchlist.JR(NC_F, packet_loop.place_relative_jump(&z80_patchlist) | T_I8);
z80_patchlist.POP(AF);
z80_patchlist.LD(DE_PTR, A);
z80_patchlist.INC(DE);
z80_patchlist.LD(A, B);
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(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(HL, (curr_rom.wBoxDataStart - 1) | 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.LD(DE, (curr_rom.wBoxDataStart - (debug ? 2 : 3)) | T_U16); // location to put stored data
z80_patchlist.LD(BC, ((curr_rom.wBoxDataEnd - curr_rom.wBoxDataStart) + 2) | T_U16);
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.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;
@@ -137,6 +198,10 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
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
@@ -195,7 +260,7 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
// z80_patchlist.index += 5;
array_counter.insert_variable(&z80_patchlist);
removal_array.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,
@@ -347,8 +412,8 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
// Write transferring message to screen:
z80_patchlist.CALL(curr_rom.clearScreen | T_U16);
z80_patchlist.LD(HL, curr_rom.textBorderUppLeft | T_U16);
z80_patchlist.LD(B, curr_rom.textBorderWidth | T_U8);
z80_patchlist.LD(C, curr_rom.textBorderHeight | T_U8);
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);
@@ -627,8 +692,8 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
z80_patchlist.CALL(curr_rom.clearScreen | T_U16);
z80_patchlist.LD(HL, curr_rom.textBorderUppLeft | T_U16);
z80_patchlist.LD(B, curr_rom.textBorderWidth | T_U8);
z80_patchlist.LD(C, curr_rom.textBorderHeight | T_U8);
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);
@@ -752,7 +817,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_RED, TRANSFER, true);
if (true)
{
for (int i = 0; i < 0x2A0; i++)

View File

@@ -12,7 +12,7 @@ Pokemon::Pokemon() {};
// A lot of the event Pokemon script is reused. Really should be split into many different functions
// Endian-ness too is all over the place... :/
void Pokemon::load_data(int index, byte *party_data, int game, int lang)
void Pokemon::load_data(int index, const byte *party_data, int game, int lang)
{
language = lang;
if (lang == JPN_ID)
@@ -127,6 +127,27 @@ void Pokemon::load_data(int index, byte *party_data, int game, int lang)
copy_from_to(&party_data[ot_offset + 0x00], &trainer_name[0], 7, false);
break;
}
// box_struct_offset = 0;
if (SHOW_DATA_PACKETS)
{
tte_set_pos(8, 120);
tte_write("struct offset: ");
tte_write(std::to_string(box_struct_offset).c_str());
tte_write("\nbox_size: ");
tte_write(std::to_string(box_size).c_str());
tte_write("\npkmn_size: ");
tte_write(std::to_string(pkmn_size).c_str());
tte_write("\nindex: ");
tte_write(std::to_string(index).c_str());
tte_write(", game: ");
tte_write(std::to_string(game).c_str());
while (!key_hit(KEY_A))
{
global_next_frame();
}
global_next_frame();
}
}
void Pokemon::convert_to_gen_three(bool simplified, bool stabilize_mythical)
{
@@ -143,8 +164,11 @@ void Pokemon::convert_to_gen_three(bool simplified, bool stabilize_mythical)
index_in_box >= num_in_box || // Checks that we're not reading beyond the Pokemon in the box
item != 0) // Checks that the Pokemon doesn't have an item
{
is_valid = false;
return;
if (!SHOW_INVALID_PKMN)
{
is_valid = false;
return;
}
}
is_valid = true;
@@ -466,7 +490,7 @@ void Pokemon::convert_to_gen_three(bool simplified, bool stabilize_mythical)
global_next_frame();
}
void Pokemon::copy_from_to(byte *source, byte *destination, int size, bool reverse_endian)
void Pokemon::copy_from_to(const byte *source, byte *destination, int size, bool reverse_endian)
{
if (reverse_endian)
{
@@ -674,7 +698,8 @@ u8 Pokemon::get_letter_from_pid(u32 pid)
((pid & 0x03000000) >> 18) +
((pid & 0x00030000) >> 12) +
((pid & 0x00000300) >> 6) +
((pid & 0x00000003) >> 0)) % 28;
((pid & 0x00000003) >> 0)) %
28;
};
u8 Pokemon::get_nature_from_pid(u32 pid)
{

View File

@@ -180,7 +180,7 @@ void Pokemon_Party::start_link()
else
{
setup();
for (int i = 0; i < 1122; i++)
for (int i = 0; i < curr_gb_rom.box_data_size; i++)
{
box_data_array[i] = 0;
}

View File

@@ -408,7 +408,7 @@ void z80_asm_handler::PUSH(int source)
{
if (TYPE(source) == T_16BIT_REG)
{
add_byte(0b11000001 | (source << 4));
add_byte(0b11000101 | (source << 4));
}
else
{
@@ -419,7 +419,7 @@ void z80_asm_handler::POP(int destination)
{
if (TYPE(destination) == T_16BIT_REG)
{
add_byte(0b11000101 | (destination << 4));
add_byte(0b11000001 | (destination << 4));
}
else
{