#include #include "libstd_replacements.h" #include "flash_mem.h" #include "pokemon_data.h" #include "rom_data.h" #include "libraries/Pokemon-Gen3-to-Gen-X/include/save.h" #include "text_engine.h" #define READ_SAVE_SECTIONS 14 #define TOTAL_SAVE_SECTIONS 14 vu32 newest_save_offset = SAVE_A_OFFSET; vu32 memory_section_array[READ_SAVE_SECTIONS]; u8 global_memory_buffer[0x1000]; u8 mem_id; // Fills the variables with the current offset information void initialize_memory_locations() { u8 save_A_index[4]; u8 save_B_index[4]; copy_save_to_ram(SAVE_A_OFFSET + SAVE_INDEX_OFFSET, &save_A_index[0], 0x04); copy_save_to_ram(SAVE_B_OFFSET + SAVE_INDEX_OFFSET, &save_B_index[0], 0x04); reverse_endian(&save_A_index[0], 0x04); reverse_endian(&save_B_index[0], 0x04); // Determines if save A or B is more recent if (*(vu32 *)save_B_index > *(vu32 *)save_A_index) { newest_save_offset = SAVE_B_OFFSET; } // Populates the memory_section_array with the correct pointer locations // The sections within the save slot are rotated on every save. So it doesn't // start at the first section. However, the next sections follow sequentially. // https://bulbapedia.bulbagarden.net/wiki/Save_data_structure_(Generation_III)#Section_ID copy_save_to_ram(newest_save_offset + SECTION_ID_OFFSET, &mem_id, 1); for (int i = 0; i < TOTAL_SAVE_SECTIONS; i++) { if (mem_id < READ_SAVE_SECTIONS) { memory_section_array[mem_id] = newest_save_offset + (i * 0x1000); } mem_id = (mem_id + 1) % TOTAL_SAVE_SECTIONS; } // Bring the Memory ID back to the first one mem_id = (mem_id + 1) % TOTAL_SAVE_SECTIONS; if (false) // This will print out a section of the FLASH mem for debugging purposes { int mem_start = 0xF80; int mem_section = 1; copy_save_to_ram(memory_section_array[mem_section], &global_memory_buffer[0], 0x1000); tte_set_pos(8, 0); tte_write("loc: "); tte_write(ptgb::to_string(static_cast(memory_section_array[mem_section] + mem_start))); tte_write("\n"); for (int i = mem_start; i < (128 + mem_start); i++) { if (i % 2 == 0) { tte_write("#{cx:0xE000}"); } else { tte_write("#{cx:0xD000}"); } tte_write(ptgb::to_string(global_memory_buffer[i])); if (i % 8 == 7) { tte_write("\n"); } else { if (global_memory_buffer[i] < 10) { tte_write(" "); } else if (global_memory_buffer[i] < 100) { tte_write(" "); } else { tte_write(""); } } } while (true) { }; } } void print_mem_section() { return; // This function isn't really needed now /* uint16_t charset[256]; byte out[4] = {0, 0, 0, 0xFF}; const char mem_name = (newest_save_offset == SAVE_A_OFFSET) ? 'A' : 'B'; load_localized_charset(charset, 3, ENGLISH); out[0] = get_char_from_charset(charset, mem_name); out[1] = get_char_from_charset(charset, '-'); out[2] = get_char_from_charset(charset, mem_id + 0xA1); // Kinda a dumb way to //tte_set_pos(0, 0); ptgb_write_simple(out, true); */ } // Reverses the endian of the given array void reverse_endian(u8 *data, size_t size) { u8 temp; for (unsigned int i = 0; i < (size / 2); i++) { temp = data[i]; data[i] = data[(size - 1) - i]; data[(size - 1) - i] = temp; } } void update_memory_buffer_checksum(bool hall_of_fame) { u32 checksum = 0x00; // Section 13 is the last PC buffer (I) and that one only has 2000 bytes of data. // source: https://bulbapedia.bulbagarden.net/wiki/Save_data_structure_(Generation_III)#Section_ID const u32 num_of_bytes = (global_memory_buffer[SECTION_ID_OFFSET] != 13) ? 3968 : 2000; // the cpu is little endian and the data is read as little endian too. // therefore, we can do a straightforward sum of the data as u32's. const u32 *cur = (const u32 *)global_memory_buffer; const u32 * const end = (const u32 *)(global_memory_buffer + num_of_bytes); while (cur < end) { checksum += *cur; ++cur; } const u16 small_checksum = ((checksum & 0xFFFF0000) >> 16) + (checksum & 0x0000FFFF); const u32 checksum_offset = hall_of_fame ? 0x0FF4 : 0x0FF6; global_memory_buffer[checksum_offset] = small_checksum & 0x00FF; global_memory_buffer[checksum_offset + 1] = (small_checksum & 0xFF00) >> 8; } bool read_flag(u16 flag_id) { if (false) { //tte_set_pos(0, 0); tte_write("#{cx:0xD000}Attempting to read byte "); tte_write(ptgb::to_string((curr_GBA_rom.offset_flags + (flag_id / 8)) % 0xF80)); tte_write(" of memory section "); tte_write(ptgb::to_string(1 + ((curr_GBA_rom.offset_flags + (flag_id / 8)) / 0xF80))); tte_write(" for flag "); tte_write(ptgb::to_string(flag_id)); tte_write(". Flag is "); copy_save_to_ram(memory_section_array[1 + ((curr_GBA_rom.offset_flags + (flag_id / 8)) / 0xF80)], &global_memory_buffer[0], 0x1000); u8 flags = global_memory_buffer[(curr_GBA_rom.offset_flags + (flag_id / 8)) % 0xF80]; tte_write(ptgb::to_string((flags >> (flag_id % 8)) & 0b1)); while (true) { }; } copy_save_to_ram(memory_section_array[1 + ((curr_GBA_rom.offset_flags + (flag_id / 8)) / 0xF80)], &global_memory_buffer[0], 0x1000); u8 flags = global_memory_buffer[(curr_GBA_rom.offset_flags + (flag_id / 8)) % 0xF80]; return (flags >> (flag_id % 8)) & 0b1; } bool compare_map_and_npc_data(int map_bank, int map_id, int npc_id) { copy_save_to_ram(memory_section_array[4], &global_memory_buffer[0], 0x1000); return (global_memory_buffer[curr_GBA_rom.offset_script + 5] == map_bank && global_memory_buffer[curr_GBA_rom.offset_script + 6] == map_id && global_memory_buffer[curr_GBA_rom.offset_script + 7] == npc_id); }