From e37cc7de9583b00166e96a6632ba25edefff43ca Mon Sep 17 00:00:00 2001 From: slipstream/RoL Date: Sun, 26 Feb 2017 14:27:20 +0000 Subject: Major changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added saveblock structures. - Changed example payload, now it warps to Hall of Fame. - Added helper library for PokĂ©mon manipulation, checksum calculation, etc. - Removed libSave, it's not needed. --- gba/source/libSave.c | 596 ----------------------------------- gba/source/libSave.h | 27 -- gba/source/libpayload.c | 312 +++++++++++++++++++ gba/source/libpayload.h | 160 ++++++++++ gba/source/payload.c | 60 +++- gba/source/payload.h | 1 + gba/source/saveblocks.h | 338 +++++++++++++++++++- gba/source/savestructs.h | 793 +++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1656 insertions(+), 631 deletions(-) delete mode 100644 gba/source/libSave.c delete mode 100644 gba/source/libSave.h create mode 100644 gba/source/libpayload.c create mode 100644 gba/source/libpayload.h create mode 100644 gba/source/savestructs.h (limited to 'gba') diff --git a/gba/source/libSave.c b/gba/source/libSave.c deleted file mode 100644 index e3bda1d..0000000 --- a/gba/source/libSave.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - libSave - Cartridge backup memory save routines. To use, call the required - routine with a pointer to an appropriately sized array of data to - be read from or written to the cartridge. - Data types are from wintermute's gba_types.h libgba library. - Original file from SendSave by Chishm -*/ - -#include -#include -#include -#include - -#define EEPROM_ADDRESS (0xDFFFF00) -#define REG_EEPROM *(vu16 *)(EEPROM_ADDRESS) -#define REG_DMA3CNT_H *(vu16 *)(REG_BASE + 0x0de) -#define REG_WAITCNT *(vu16 *)(REG_BASE + 0x204) - -//----------------------------------------------------------------------- -// Common EEPROM Routines -//----------------------------------------------------------------------- - -void EEPROM_SendPacket( u16* packet, int size ) -{ - REG_WAITCNT = (REG_WAITCNT & 0xF8FF) | 0x0300; - REG_DMA3SAD = (u32)packet; - REG_DMA3DAD = EEPROM_ADDRESS; - REG_DMA3CNT = 0x80000000 + size; - while((REG_DMA3CNT_H & 0x8000) != 0) ; -} - -void EEPROM_ReceivePacket( u16* packet, int size ) -{ - REG_WAITCNT = (REG_WAITCNT & 0xF8FF) | 0x0300; - REG_DMA3SAD = EEPROM_ADDRESS; - REG_DMA3DAD = (u32)packet; - REG_DMA3CNT = 0x80000000 + size; - while((REG_DMA3CNT_H & 0x8000) != 0) ; -} - -//----------------------------------------------------------------------- -// Routines for 512B EEPROM -//----------------------------------------------------------------------- - -void EEPROM_Read_512B( volatile u8 offset, u8* dest ) // dest must point to 8 bytes -{ - u16 packet[68]; - u8* out_pos; - u16* in_pos; - u8 out_byte; - int byte, bit; - - memset( packet, 0, 68*2 ); - - // Read request - packet[0] = 1; - packet[1] = 1; - - // 6 bits eeprom address (MSB first) - packet[2] = (offset>>5)&1; - packet[3] = (offset>>4)&1; - packet[4] = (offset>>3)&1; - packet[5] = (offset>>2)&1; - packet[6] = (offset>>1)&1; - packet[7] = (offset)&1; - - // End of request - packet[8] = 0; - - // Do transfers - EEPROM_SendPacket( packet, 9 ); - memset( packet, 0, 68*2 ); - EEPROM_ReceivePacket( packet, 68 ); - - // Extract data - in_pos = &packet[4]; - out_pos = dest; - for( byte = 7; byte >= 0; --byte ) - { - out_byte = 0; - for( bit = 7; bit >= 0; --bit ) - { -// out_byte += (*in_pos++)<>5)&1; - packet[3] = (offset>>4)&1; - packet[4] = (offset>>3)&1; - packet[5] = (offset>>2)&1; - packet[6] = (offset>>1)&1; - packet[7] = (offset)&1; - - // Extract data - in_pos = source; - out_pos = &packet[8]; - for( byte = 7; byte >= 0; --byte ) - { - in_byte = *in_pos++; - for( bit = 7; bit >= 0; --bit ) - { - *out_pos++ = (in_byte>>bit)&1; - } - } - - // End of request - packet[72] = 0; - - // Do transfers - EEPROM_SendPacket( packet, 73 ); - - // Wait for EEPROM to finish (should timeout after 10 ms) - while( (REG_EEPROM & 1) == 0 ); -} - -//--------------------------------------------------------------------------------- -void GetSave_EEPROM_512B(u8* data) -//--------------------------------------------------------------------------------- -{ - volatile u8 x; - u32 sleep; - - for (x=0;x<64;++x){ - EEPROM_Read_512B(x,&data[x*8]); - for(sleep=0;sleep<512000;sleep++); - } -} - -//--------------------------------------------------------------------------------- -void PutSave_EEPROM_512B(u8* data) -//--------------------------------------------------------------------------------- -{ - volatile u8 x; - u32 sleep; - - for (x=0;x<64;x++){ - EEPROM_Write_512B(x,&data[x*8]); - for(sleep=0;sleep<512000;sleep++); - } -} -//----------------------------------------------------------------------- -// Routines for 8KB EEPROM -//----------------------------------------------------------------------- - -void EEPROM_Read_8KB( volatile u16 offset, u8* dest ) // dest must point to 8 bytes -{ - u16 packet[68]; - u8* out_pos; - u16* in_pos; - u8 out_byte; - int byte, bit; - - memset( packet, 0, 68*2 ); - - // Read request - packet[0] = 1; - packet[1] = 1; - - // 14 bits eeprom address (MSB first) - packet[2] = (offset>>13)&1; - packet[3] = (offset>>12)&1; - packet[4] = (offset>>11)&1; - packet[5] = (offset>>10)&1; - packet[6] = (offset>>9)&1; - packet[7] = (offset>>8)&1; - packet[8] = (offset>>7)&1; - packet[9] = (offset>>6)&1; - packet[10] = (offset>>5)&1; - packet[11] = (offset>>4)&1; - packet[12] = (offset>>3)&1; - packet[13] = (offset>>2)&1; - packet[14] = (offset>>1)&1; - packet[15] = (offset)&1; - - // End of request - packet[16] = 0; - - // Do transfers - EEPROM_SendPacket( packet, 17 ); - memset( packet, 0, 68*2 ); - EEPROM_ReceivePacket( packet, 68 ); - - // Extract data - in_pos = &packet[4]; - out_pos = dest; - for( byte = 7; byte >= 0; --byte ) - { - out_byte = 0; - for( bit = 7; bit >= 0; --bit ) - { -// out_byte += (*in_pos++)<>13)&1; - packet[3] = (offset>>12)&1; - packet[4] = (offset>>11)&1; - packet[5] = (offset>>10)&1; - packet[6] = (offset>>9)&1; - packet[7] = (offset>>8)&1; - packet[8] = (offset>>7)&1; - packet[9] = (offset>>6)&1; - packet[10] = (offset>>5)&1; - packet[11] = (offset>>4)&1; - packet[12] = (offset>>3)&1; - packet[13] = (offset>>2)&1; - packet[14] = (offset>>1)&1; - packet[15] = (offset)&1; - - // Extract data - in_pos = source; - out_pos = &packet[16]; - for( byte = 7; byte >= 0; --byte ) - { - in_byte = *in_pos++; - for( bit = 7; bit >= 0; --bit ) - { - *out_pos++ = (in_byte>>bit)&1; - } - } - - // End of request - packet[80] = 0; - - // Do transfers - EEPROM_SendPacket( packet, 81 ); - - // Wait for EEPROM to finish (should timeout after 10 ms) - while( (REG_EEPROM & 1) == 0 ); -} - -//--------------------------------------------------------------------------------- -void GetSave_EEPROM_8KB(u8* data) -//--------------------------------------------------------------------------------- -{ - volatile u16 x; - u32 sleep; - - for (x=0;x<1024;x++){ - EEPROM_Read_8KB(x,&data[x*8]); - for(sleep=0;sleep<512000;sleep++); - } - -} - -//--------------------------------------------------------------------------------- -void PutSave_EEPROM_8KB(u8* data) -//--------------------------------------------------------------------------------- -{ - volatile u16 x; - u32 sleep; - - for (x=0;x<1024;x++){ - EEPROM_Write_8KB(x,&data[x*8]); - for(sleep=0;sleep<512000;sleep++); - } -} - -//--------------------------------------------------------------------------------- -void GetSave_SRAM_32KB(u8* data) -//--------------------------------------------------------------------------------- -{ - volatile u8 *sram= (u8*) 0x0E000000; - volatile u16 x; - - for (x = 0; x < 0x8000; ++x) - { - data[x] = sram[x]; - } - -} - -//--------------------------------------------------------------------------------- -void PutSave_SRAM_32KB(u8* data) -//--------------------------------------------------------------------------------- -{ - volatile u8 *sram= (u8*) 0x0E000000; - volatile u16 x; - - for (x = 0; x < 0x8000; ++x) - { - sram[x] = data[x]; - } -} - -//--------------------------------------------------------------------------------- -void GetSave_FLASH_64KB(u8* data) -//--------------------------------------------------------------------------------- -{ - volatile u8 *sram= (u8*) 0x0E000000; - volatile u32 x; - - for (x = 0; x < 0x10000; ++x) - { - data[x] = sram[x]; - } -} - -//--------------------------------------------------------------------------------- -void PutSave_FLASH_64KB(u8* foo) -//--------------------------------------------------------------------------------- -{ - volatile u8 *fctrl0 = (u8*) 0xE005555; - volatile u8 *fctrl1 = (u8*) 0xE002AAA; - volatile u8 *fctrl2 = (u8*) 0xE000000; - - //init flash - *fctrl0 = 0xAA; - *fctrl1 = 0x55; - *fctrl0 = 0x90; - *fctrl2 = 0xF0; - - //erase chip - *fctrl0 = 0xAA; - *fctrl1 = 0x55; - *fctrl0 = 0x80; - *fctrl0 = 0xAA; - *fctrl1 = 0x55; - *fctrl0 = 0x10; - - //wait for erase done - u8 val1; - u8 val2; - val1 = *fctrl2; - val2 = *fctrl2; - while (val1 != val2) { - val1 = *fctrl2; - val2 = *fctrl2; - } - val1 = *fctrl2; - val2 = *fctrl2; - while (val1 != val2) { - val1 = *fctrl2; - val2 = *fctrl2; - } - - volatile u8 *data = fctrl2; - u32 i; - //write data - for (i=0; i<65536; i++) { - *fctrl0 = 0xAA; - *fctrl1 = 0x55; - *fctrl0 = 0xA0; - data [i] = foo [ i ]; - val1 = data [ i ]; - val2 = data [ i ]; - - while (val1 != val2) { - val1 = data [ i ]; - val2 = data [ i ]; - } - val1 = data [ i ]; - val2 = data [ i ]; - while (val1 != val2) { - val1 = data [ i ]; - val2 = data [ i ]; - } - val1 = data [ i ]; - val2 = data [ i ]; - while (val1 != val2) { - val1 = data [ i ]; - val2 = data [ i ]; - } - } -} - -//--------------------------------------------------------------------------------- -void GetSave_FLASH_128KB(u8* data) -//--------------------------------------------------------------------------------- -{ - const u32 size = 0x10000; - - volatile u8 *fctrl0 = (u8*) 0xE005555; - volatile u8 *fctrl1 = (u8*) 0xE002AAA; - volatile u8 *fctrl2 = (u8*) 0xE000000; - volatile u32 i; - volatile u8 *sram= (u8*) 0x0E000000; - - //init flash - *fctrl0 = 0xAA; - *fctrl1 = 0x55; - *fctrl0 = 0x90; - *fctrl2 = 0xF0; - - // read first bank - *fctrl0 = 0xAA; - *fctrl1 = 0x55; - *fctrl0 = 0xB0; - *fctrl2 = 0x00; - - for (i=0; i=0;x--){ - switch (pak[x]) { - case 0x53414C46: - if (pak[x+1] == 0x5F4D3148){ - return 0x20000; // FLASH_128KB - } else if ((pak[x+1] & 0x0000FFFF) == 0x00005F48){ - return 0x10000; // FLASH_64KB - } else if (pak[x+1] == 0x32313548){ - return 0x10000; // FLASH_64KB - } - break; - case 0x52504545: - if ((pak[x+1] & 0x00FFFFFF) == 0x005F4D4F){ - GetSave_EEPROM_8KB(data); - for(i = 8; i < 0x800; i += 8) { - if(memcmp(data, data+i, 8) != 0) - return 0x2000; // EEPROM_8KB - } - return 0x200; // EEPROM_512B - } - break; - case 0x4D415253: - if ((pak[x+1] & 0x000000FF) == 0x0000005F){ - return 0x8000; // SRAM_32KB - } - } - } - return 0; -} - diff --git a/gba/source/libSave.h b/gba/source/libSave.h deleted file mode 100644 index 5ecf822..0000000 --- a/gba/source/libSave.h +++ /dev/null @@ -1,27 +0,0 @@ - - -//--------------------------------------------------------------------------------- -#ifdef __cplusplus -extern "C" { -#endif -//--------------------------------------------------------------------------------- - -void GetSave_EEPROM_512B(u8* data); -void PutSave_EEPROM_512B(u8* data); -void GetSave_EEPROM_8KB(u8* data); -void PutSave_EEPROM_8KB(u8* data); -void GetSave_SRAM_32KB(u8* data); -void PutSave_SRAM_32KB(u8* data); -void GetSave_FLASH_64KB(u8* data); -void PutSave_FLASH_64KB(u8* foo); -void GetSave_FLASH_128KB(u8* data); -void PutSave_FLASH_128KB(u8* foo); - -u32 SaveSize(u8* data, s32 gamesize); - - -//--------------------------------------------------------------------------------- -#ifdef __cplusplus -} // extern "C" -#endif -//--------------------------------------------------------------------------------- diff --git a/gba/source/libpayload.c b/gba/source/libpayload.c new file mode 100644 index 0000000..f13a34f --- /dev/null +++ b/gba/source/libpayload.c @@ -0,0 +1,312 @@ +/* + * Example Gen3-multiboot payload by slipstream/RoL 2017. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + * libpayload.c: contains helper functions for the payload + */ + +#include +#include "payload.h" + +// private functions +static void CryptBoxPokemon(struct BoxPokemon* pkm); +static u16 crc16(const u8* data, u16 len); +static u32 CalculateRamScriptDataChecksum(struct RamScriptData* ramScript); + +/** + * Decrypts the substructures of a Pokémon structure, so they can be viewed or modified easily. + * Remember to call EncryptPokemon() afterwards. + * @param struct Pokemon* pkm The Pokémon to decrypt the substructures of. +*/ +void DecryptPokemon(struct Pokemon* pkm) { + struct BoxPokemon* boxMon = &(pkm->box); + CryptBoxPokemon(boxMon); +} + +/** + * Private function that does the actual work of crypting the substructures of a BoxPokemon. + * @param struct BoxPokemon* pkm The BoxPokemon whose substructures will be crypted. +*/ +static void CryptBoxPokemon(struct BoxPokemon* pkm) { + for (u32 i = 0; i < 12; i++) { + pkm->secure.raw[i] ^= (pkm->otId ^ pkm->personality); + } +} + +/** + * Decrypts the substructures of a core Pokémon structure, so they can be viewed or modified easily. + * Used by DecryptPokemon(). + * Remember to call EncryptPokemon() afterwards. + * @param struct BoxPokemon* pkm The BoxPokemon to decrypt the substructures of. +*/ +void DecryptBoxPokemon(struct BoxPokemon* pkm) { + CryptBoxPokemon(pkm); +} + +/** + * Encrypts the substructures of a Pokémon structure, and fixes the checksum. + * Must be used after DecryptPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg. + * @param struct Pokemon* pkm The Pokémon to encrypt the substructures and fix the checksum of. +*/ +void EncryptPokemon(struct Pokemon* pkm) { + struct BoxPokemon* boxMon = &(pkm->box); + EncryptBoxPokemon(boxMon); +} + +/** + * Encrypts the substructures of a core Pokémon structure, and fixes the checksum. + * Must be used after DecryptBoxPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg. + * @param struct BoxPokemon* pkm The BoxPokemon to encrypt the substructures and fix the checksum of. +*/ +void EncryptBoxPokemon(struct BoxPokemon* pkm) { + FixBoxPokemonChecksum(pkm); + CryptBoxPokemon(pkm); +} + +/** + * Gets a substructure of a Pokémon structure. + * Call DecryptPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokemon to get a substructure of. + * @param u8 substructId The substructure to get. + * @return union PokemonSubstruct* The substructure. +*/ +union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId) { + struct BoxPokemon* boxMon = &(pkm->box); + return GetBoxPokemonSubstruct(boxMon,substructId); +} + +/** + * Gets a substructure of a core Pokémon structure. + * Call DecryptBoxPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokemon to get a substructure of. + * @param u8 substructId The substructure to get. + * @return union PokemonSubstruct* The substructure. +*/ +union PokemonSubstruct* GetBoxPokemonSubstruct(struct BoxPokemon* pkm,u8 substructId) { + if (substructId > 3) return NULL; + u32 personality = pkm->personality; + // Staring at the substruct indexes, I noticed the last two columns are the reverse of the first two! + // that is, substructId==2 column is the reverse of substructId==1, substructId==3 is the reverse of substructId==0 + // At least that means there's no need to hardcode all four. + u8 substruct_idxes[2][24] = { + { 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3 }, + { 1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2 } + }; + u32 modulo = (personality % 24); + if (substructId < 2) { + return &( pkm->secure.substructs[ substruct_idxes[substructId][modulo] ] ); + } + return &( pkm->secure.substructs[ substruct_idxes[3 - substructId][23 - modulo] ] ); +} + +/** + * Gets the checksum of a core Pokémon structure. + * @param struct BoxPokemon* pkm The BoxPokemon to calculate the checksum of. + * @return u16 The checksum. +*/ +u16 CalculateBoxPokemonChecksum(struct BoxPokemon* pkm) { + u16 checksum = 0; + union PokemonSubstruct* substructs[4] = { + GetBoxPokemonSubstruct(pkm,0), + GetBoxPokemonSubstruct(pkm,1), + GetBoxPokemonSubstruct(pkm,2), + GetBoxPokemonSubstruct(pkm,3) + }; + + for (int substruct = 0; substruct < 4; substruct++) { + for (int i = 0; i < 6; i++) { + checksum += substructs[substruct]->raw[i]; + } + } + return checksum; +} + +/** + * Fixes the checksum of a core Pokémon structure. + * @param struct BoxPokemon* pkm The BoxPokemon to fix the checksum of. +*/ +void FixBoxPokemonChecksum(struct BoxPokemon* pkm) { + pkm->checksum = CalculateBoxPokemonChecksum(pkm); +} + +/** + * Gets the zeroth substructure ("Growth") of a Pokémon structure. + * Call DecryptPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokémon to get a substructure of. + * @return struct PokemonSubstruct0* The substructure. +*/ +struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm) { + struct BoxPokemon* boxMon = &(pkm->box); + return GetBoxPokemonSubstruct0(boxMon); +} + +/** + * Gets the zeroth substructure ("Growth") of a core Pokémon structure. + * Call DecryptBoxPokemon() first or the substructure data will be encrypted. + * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of. + * @return struct PokemonSubstruct0* The substructure. +*/ +struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm) { + return &( GetBoxPokemonSubstruct(pkm,0)->type0 ); +} + +/** + * Gets the first substructure ("Attacks") of a Pokémon structure. + * Call DecryptPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokémon to get a substructure of. + * @return struct PokemonSubstruct0* The substructure. +*/ +struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm) { + struct BoxPokemon* boxMon = &(pkm->box); + return GetBoxPokemonSubstruct1(boxMon); +} + +/** + * Gets the first substructure ("Attacks") of a core Pokémon structure. + * Call DecryptBoxPokemon() first or the substructure data will be encrypted. + * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of. + * @return struct PokemonSubstruct1* The substructure. +*/ +struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm) { + return &( GetBoxPokemonSubstruct(pkm,1)->type1 ); +} + +/** + * Gets the second substructure ("EVs & Condition") of a Pokémon structure. + * Call DecryptPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokémon to get a substructure of. + * @return struct PokemonSubstruct0* The substructure. +*/ +struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm) { + struct BoxPokemon* boxMon = &(pkm->box); + return GetBoxPokemonSubstruct2(boxMon); +} + +/** + * Gets the second substructure ("EVs & Condition") of a core Pokémon structure. + * Call DecryptBoxPokemon() first or the substructure data will be encrypted. + * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of. + * @return struct PokemonSubstruct2* The substructure. +*/ +struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm) { + return &( GetBoxPokemonSubstruct(pkm,2)->type2 ); +} + +/** + * Gets the third substructure ("Miscellaneous") of a Pokémon structure. + * Call DecryptPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokémon to get a substructure of. + * @return struct PokemonSubstruct0* The substructure. +*/ +struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm) { + struct BoxPokemon* boxMon = &(pkm->box); + return GetBoxPokemonSubstruct3(boxMon); +} + +/** + * Gets the third substructure ("Miscellaneous") of a core Pokémon structure. + * Call DecryptBoxPokemon() first or the substructure data will be encrypted. + * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of. + * @return struct PokemonSubstruct3* The substructure. +*/ +struct PokemonSubstruct3* GetBoxPokemonSubstruct3(struct BoxPokemon* pkm) { + return &( GetBoxPokemonSubstruct(pkm,3)->type3 ); +} + +/** + * Calculates the checksum for an R/S-specific Enigma Berry structure in SaveBlock1. + * @param struct EnigmaBerry* enigmaBerry The R/S-specific Enigma Berry to calculate the checksum for. + * @return u32 The checksum. +*/ +u32 CalculateEnigmaBerryChecksumRS(struct EnigmaBerry* enigmaBerry) { + if (!GAME_RS) return 0; // Enigma Berry structure changed in FR/LG, use CalculateEnigmaBerryChecksumFRLGE() instead. + u32 checksum = 0; + // Save off and zero out the original Enigma Berry description pointers. + const u8* description[2] = { enigmaBerry->berry.description1, enigmaBerry->berry.description2 }; + enigmaBerry->berry.description1 = enigmaBerry->berry.description2 = NULL; + u8* enigmaBerryBytes = (u8*)enigmaBerry; + // Calculate the checksum. + for (u32 i = 0; i < 1324; i++) { + checksum += enigmaBerryBytes[i]; + } + // Restore the saved description. + enigmaBerry->berry.description1 = description[0]; + enigmaBerry->berry.description2 = description[1]; + return checksum; +} + +/** + * Calculates the checksum for an FR/LG/Emerald-specific Enigma Berry structure in SaveBlock1. + * @param struct EnigmaBerryFRLGE* enigmaBerry The FR/LG/Emerald-specific Enigma Berry to calculate the checksum for. + * @return u32 The checksum. +*/ +u32 CalculateEnigmaBerryChecksumFRLGE(struct EnigmaBerryFRLGE* enigmaBerry) { + if (GAME_RS) return 0; // Enigma Berry structure is different in R/S, use CalculateEnigmaBerryChecksumRS() instead. + u32 checksum = 0; + u8* enigmaBerryBytes = (u8*)enigmaBerry; + for (int i = 0; i < 0x30; i++) { + checksum += enigmaBerryBytes[i]; + } + return checksum; +} + +/** + * Calculates the checksum for an unspecified Enigma Berry structure in SaveBlock1. (detected by current game) + * @param void* enigmaBerry The Enigma Berry structure to calculate the checksum for. + * @return u32 The checksum. + */ +u32 CalculateEnigmaBerryChecksum(void* enigmaBerry) { + if (GAME_RS) return CalculateEnigmaBerryChecksumRS( (struct EnigmaBerry*) enigmaBerry ); + return CalculateEnigmaBerryChecksumFRLGE( (struct EnigmaBerryFRLGE*) enigmaBerry ); +} + +/** + * Calculates the checksum for a RAM script structure in SaveBlock1. + * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for. + * @return u32 The checksum. + */ +u32 CalculateRamScriptChecksum(struct RamScript* ramScript) { + asm(""); // make sure the call to CalculateRamScriptDataChecksum() is *not* inlined. + // For some reason, if it gets inlined, something happens, and the wrong length is used when checksumming... + return CalculateRamScriptDataChecksum(&ramScript->data); +} + +/** + * Calculates the checksum for a RAM script structure in SaveBlock1. + * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for. + * @return u32 The checksum. + */ +static __attribute__ ((noinline)) u32 CalculateRamScriptDataChecksum(struct RamScriptData* ramScript) { + u32 checksum = 0; + u32 i = 0; + u8* ramScriptBytes = (u8*)(ramScript); + if (GAME_RS) { + for (i = 0; i < sizeof(struct RamScriptData); i++) checksum += ramScriptBytes[i]; + return checksum; + } + + return (u32)crc16(ramScriptBytes,sizeof(struct RamScriptData) + 1); +} + +/** + * Private function to CRC-16, (used by FR/LG/Emerald ramscript checksum). Adapted from http://forums.glitchcity.info/index.php?topic=7114.0 + * @param u8* Data to checksum + * @param u16 Length of data + * @return u16 The checksum +*/ +static u16 crc16(const u8* data, u16 len) { + u16 crc = 0x1121; + for (u16 i = 0; i < len; ++i) { + crc ^= data[i]; + for (u16 j = 0; j < 8; ++j) { + if(crc & 1) { + crc = (crc >> 1) ^ 0x8408; + } else { + crc >>= 1; + } + } + } + return ~crc; +} \ No newline at end of file diff --git a/gba/source/libpayload.h b/gba/source/libpayload.h new file mode 100644 index 0000000..4be6fb3 --- /dev/null +++ b/gba/source/libpayload.h @@ -0,0 +1,160 @@ +/* + * Example Gen3-multiboot payload by slipstream/RoL 2017. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + * libpayload.h: header for payload helper functions + */ + +/** + * Decrypts the substructures of a Pokémon structure, so they can be viewed or modified easily. + * Remember to call EncryptPokemon() afterwards. + * @param struct Pokemon* pkm The Pokémon to decrypt the substructures of. +*/ +void DecryptPokemon(struct Pokemon* pkm); + +/** + * Decrypts the substructures of a core Pokémon structure, so they can be viewed or modified easily. + * Used by DecryptPokemon(). + * Remember to call EncryptPokemon() afterwards. + * @param struct BoxPokemon* pkm The BoxPokemon to decrypt the substructures of. +*/ +void DecryptBoxPokemon(struct BoxPokemon* pkm); + +/** + * Encrypts the substructures of a Pokémon structure, and fixes the checksum. + * Must be used after DecryptPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg. + * @param struct Pokemon* pkm The Pokémon to encrypt the substructures and fix the checksum of. +*/ +void EncryptPokemon(struct Pokemon* pkm); + +/** + * Encrypts the substructures of a core Pokémon structure, and fixes the checksum. + * Must be used after DecryptBoxPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg. + * @param struct BoxPokemon* pkm The BoxPokemon to encrypt the substructures and fix the checksum of. +*/ +void EncryptBoxPokemon(struct BoxPokemon* pkm); + +/** + * Gets a substructure of a Pokémon structure. + * Call DecryptPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokemon to get a substructure of. + * @param u8 substructId The substructure to get. + * @return union PokemonSubstruct* The substructure. +*/ +union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId); + +/** + * Gets a substructure of a core Pokémon structure. + * Call DecryptBoxPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokemon to get a substructure of. + * @param u8 substructId The substructure to get. + * @return union PokemonSubstruct* The substructure. +*/ +union PokemonSubstruct* GetBoxPokemonSubstruct(struct BoxPokemon* pkm,u8 substructId); + +/** + * Gets the checksum of a core Pokémon structure. + * @param struct BoxPokemon* pkm The BoxPokemon to calculate the checksum of. + * @return u16 The checksum. +*/ +u16 CalculateBoxPokemonChecksum(struct BoxPokemon* pkm); + +/** + * Fixes the checksum of a core Pokémon structure. + * @param struct BoxPokemon* pkm The BoxPokemon to fix the checksum of. +*/ +void FixBoxPokemonChecksum(struct BoxPokemon* pkm); + +/** + * Gets the zeroth substructure ("Growth") of a Pokémon structure. + * Call DecryptPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokémon to get a substructure of. + * @return struct PokemonSubstruct0* The substructure. +*/ +struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm); + +/** + * Gets the zeroth substructure ("Growth") of a core Pokémon structure. + * Call DecryptBoxPokemon() first or the substructure data will be encrypted. + * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of. + * @return struct PokemonSubstruct0* The substructure. +*/ +struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm); + +/** + * Gets the first substructure ("Attacks") of a Pokémon structure. + * Call DecryptPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokémon to get a substructure of. + * @return struct PokemonSubstruct0* The substructure. +*/ +struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm); + +/** + * Gets the first substructure ("Attacks") of a core Pokémon structure. + * Call DecryptBoxPokemon() first or the substructure data will be encrypted. + * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of. + * @return struct PokemonSubstruct1* The substructure. +*/ +struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm); + +/** + * Gets the second substructure ("EVs & Condition") of a Pokémon structure. + * Call DecryptPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokémon to get a substructure of. + * @return struct PokemonSubstruct0* The substructure. +*/ +struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm); + +/** + * Gets the second substructure ("EVs & Condition") of a core Pokémon structure. + * Call DecryptBoxPokemon() first or the substructure data will be encrypted. + * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of. + * @return struct PokemonSubstruct2* The substructure. +*/ +struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm); + +/** + * Gets the third substructure ("Miscellaneous") of a Pokémon structure. + * Call DecryptPokemon() first or the substructure data will be encrypted. + * @param struct Pokemon* pkm The Pokémon to get a substructure of. + * @return struct PokemonSubstruct0* The substructure. +*/ +struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm); + +/** + * Gets the third substructure ("Miscellaneous") of a core Pokémon structure. + * Call DecryptBoxPokemon() first or the substructure data will be encrypted. + * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of. + * @return struct PokemonSubstruct3* The substructure. +*/ +struct PokemonSubstruct3* GetBoxPokemonSubstruct3(struct BoxPokemon* pkm); + +/** + * Calculates the checksum for an R/S-specific Enigma Berry structure in SaveBlock1. + * @param struct EnigmaBerry* enigmaBerry The R/S-specific Enigma Berry to calculate the checksum for. + * @return u32 The checksum. +*/ +u32 CalculateEnigmaBerryChecksumRS(struct EnigmaBerry* enigmaBerry); + +/** + * Calculates the checksum for an FR/LG/Emerald-specific Enigma Berry structure in SaveBlock1. + * @param struct EnigmaBerryFRLGE* enigmaBerry The FR/LG/Emerald-specific Enigma Berry to calculate the checksum for. + * @return u32 The checksum. +*/ +u32 CalculateEnigmaBerryChecksumFRLGE(struct EnigmaBerryFRLGE* enigmaBerry); + +/** + * Calculates the checksum for an unspecified Enigma Berry structure in SaveBlock1. (detected by current game) + * @param void* enigmaBerry The Enigma Berry structure to calculate the checksum for. + * @return u32 The checksum. + */ +u32 CalculateEnigmaBerryChecksum(void* enigmaBerry); + +/** + * Calculates the checksum for a RAM script structure in SaveBlock1. + * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for. + * @return u32 The checksum. + */ +u32 CalculateRamScriptChecksum(struct RamScript* ramScript); \ No newline at end of file diff --git a/gba/source/payload.c b/gba/source/payload.c index 7015774..665af70 100644 --- a/gba/source/payload.c +++ b/gba/source/payload.c @@ -12,7 +12,61 @@ // Your payload code should obviously go into the body of this, the payload function. void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) { - // This example payload will modify the first character of the player's name. - // It will change to 'z'. You can see the character encoding table here: http://bulbapedia.bulbagarden.net/wiki/Character_encoding_in_Generation_III - SaveBlock2[0] = 0xee; // 'z' + // HoF-warp example payload! + + // Structure offsets are different between R/S, FR/LG, and Emerald. + // The beginning of the structures are the same but do NOT take shortcuts here, it's not good practise. + // If you want to support multiple games, make specific checks for games, use the right structure for each game. + SaveBlock1_RS* sb1rs = &SaveBlock1->rs; + SaveBlock1_FRLG* sb1frlg = &SaveBlock1->frlg; + SaveBlock1_E* sb1e = &SaveBlock1->e; + if (GAME_FRLG) { + sb1frlg->location.mapGroup = 1; // generic indoors? + sb1frlg->location.mapNum = 80; // Hall of Fame + // set coords to the same place that the champions' room script sets them to + sb1frlg->location.x = sb1frlg->pos.x = 5; + sb1frlg->location.y = sb1frlg->pos.y = 12; + sb1frlg->mapDataId = 0xDA; // from HoF map-header + sb1frlg->location.warpId = 0xff; + // make sure the HoF script doesn't crash, which it will do if 0 pokémon + if (sb1frlg->playerPartyCount == 0) { + sb1frlg->playerPartyCount = 1; + // this isn't enough, the heal animation recalculates the party count ignoring empty spots + // so let's hack together one. i don't care about it becoming a bad egg at all. + sb1frlg->playerParty[0].box.personality++; + } + return; + } else if (GAME_RS) { + sb1rs->location.mapGroup = 16; // Ever Grande City + sb1rs->location.mapNum = 11; // Hall of Fame + // set coords to the same place that the champions' room script sets them to + sb1rs->location.x = sb1rs->pos.x = 7; + sb1rs->location.y = sb1rs->pos.y = 16; + sb1rs->mapDataId = 299; // from HoF map-header + sb1rs->location.warpId = 0xff; + // make sure the HoF script doesn't crash, which it will do if 0 pokémon + if (sb1rs->playerPartyCount == 0) { + sb1rs->playerPartyCount = 1; + // this isn't enough, the heal animation recalculates the party count ignoring empty spots + // so let's hack together one. i don't care about it becoming a bad egg at all. + sb1rs->playerParty[0].box.personality++; + } + return; + } else if (GAME_EM) { + sb1e->location.mapGroup = 16; // Ever Grande City + sb1e->location.mapNum = 11; // Hall of Fame + // set coords to the same place that the champions' room script sets them to + sb1e->location.x = sb1e->pos.x = 7; + sb1e->location.y = sb1e->pos.y = 16; + sb1e->mapDataId = 298; // from HoF map-header + sb1e->location.warpId = 0xff; + // make sure the HoF script doesn't crash, which it will do if 0 pokémon + if (sb1e->playerPartyCount == 0) { + sb1e->playerPartyCount = 1; + // this isn't enough, the heal animation recalculates the party count ignoring empty spots + // so let's hack together one. i don't care about it becoming a bad egg at all. + sb1e->playerParty[0].box.personality++; + } + return; + } } \ No newline at end of file diff --git a/gba/source/payload.h b/gba/source/payload.h index d95476c..ea87200 100644 --- a/gba/source/payload.h +++ b/gba/source/payload.h @@ -8,6 +8,7 @@ */ #include "saveblocks.h" +#include "libpayload.h" #define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00') #define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00') diff --git a/gba/source/saveblocks.h b/gba/source/saveblocks.h index 45c127c..cf0a5c3 100644 --- a/gba/source/saveblocks.h +++ b/gba/source/saveblocks.h @@ -7,9 +7,337 @@ * saveblocks.h: describes saveblock structures for all of Gen 3 (yay!) */ -// TODO: this entire file. Placeholders for now, fill in later, if I can be bothered. -// I don't really want to make a fork of pokeruby's headers for now... +// Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity +#include "savestructs.h" -typedef u8 SaveBlock1, *pSaveBlock1; -typedef u8 SaveBlock2, *pSaveBlock2; -typedef u8 SaveBlock3, *pSaveBlock3; \ No newline at end of file +typedef struct +{ + /*0x00*/ struct Coords16 pos; + /*0x04*/ struct WarpData location; + /*0x0C*/ struct WarpData warp[4]; + /*0x2C*/ u16 battleMusic; + /*0x2E*/ u8 weather; + /*0x2F*/ u8 filler_2F; + /*0x30*/ u8 flashUsed; + /*0x32*/ u16 mapDataId; + /*0x34*/ u16 mapView[0x100]; + /*0x234*/ u8 playerPartyCount; + /*0x238*/ struct Pokemon playerParty[6]; + /*0x490*/ u32 money; + /*0x494*/ u16 coins; + /*0x496*/ u16 registeredItem; // registered for use with SELECT button + /*0x498*/ struct ItemSlot pcItems[50]; + /*0x560*/ struct ItemSlot bagPocket_Items[20]; + /*0x5B0*/ struct ItemSlot bagPocket_KeyItems[20]; + /*0x600*/ struct ItemSlot bagPocket_PokeBalls[16]; + /*0x640*/ struct ItemSlot bagPocket_TMHM[64]; + /*0x740*/ struct ItemSlot bagPocket_Berries[46]; + /*0x7F8*/ struct Pokeblock pokeblocks[40]; + /*0x938*/ u8 unk938[52]; // pokedex related + /*0x96C*/ u16 berryBlenderRecords[3]; + /*0x972*/ u8 filler_972[0x6]; + /*0x978*/ u16 trainerRematchStepCounter; + /*0x97A*/ u8 trainerRematches[100]; + /*0x9E0*/ struct MapObject mapObjects[16]; + /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64]; + /*0x1220*/ u8 flags[0x120]; + /*0x1340*/ u16 vars[0x100]; + /*0x1540*/ u32 gameStats[50]; + /*0x1608*/ struct BerryTree berryTrees[128]; + /*0x1A08*/ struct SecretBaseRecord secretBases[20]; + /*0x2688*/ u8 playerRoomDecor[12]; + /*0x2694*/ u8 playerRoomDecorPos[12]; + /*0x26A0*/ u8 decorDesk[10]; + /*0x26AA*/ u8 decorChair[10]; + /*0x26B4*/ u8 decorPlant[10]; + /*0x26BE*/ u8 decorOrnament[30]; + /*0x26DC*/ u8 decorMat[30]; + /*0x26FA*/ u8 decorPoster[10]; + /*0x2704*/ u8 decorDoll[40]; + /*0x272C*/ u8 decorCushion[10]; + /*0x2736*/ u8 padding_2736[2]; + /*0x2738*/ TVShow tvShows[24]; + /*0x2A98*/ u8 filler_2A98[0x64]; + /*0x2AFC*/ u16 outbreakPokemonSpecies; + /*0x2AFE*/ u8 outbreakLocationMapNum; + /*0x2AFF*/ u8 outbreakLocationMapGroup; + /*0x2B00*/ u8 outbreakPokemonLevel; + /*0x2B01*/ u8 outbreakUnk1; + /*0x2B02*/ u16 outbreakUnk2; + /*0x2B04*/ u16 outbreakPokemonMoves[4]; + /*0x2B0C*/ u8 outbreakUnk4; + /*0x2B0D*/ u8 outbreakPokemonProbability; + /*0x2B0E*/ u16 outbreakUnk5; + /*0x2B10*/ u8 filler_2B0E[0xC]; + /*0x2B1C*/ u16 unk2B1C[4]; + /*0x2B24*/ u8 filler_2B24[0x28]; + /*0x2B4C*/ struct MailStruct mail[16]; + /*0x2D8C*/ u8 filler_2D8C[0x8]; + /*0x2D94*/ OldMan oldMan; + /*0x2DC0*/ u8 unk_2DC0[0x14]; + /*0x2DD4*/ struct EasyChatPair easyChatPairs[5]; //Dewford trend [0] and some other stuff + /*0x2DFC*/ u8 filler_2DFC[0x100]; + /*0x2EFC*/ struct SB1_2EFC_Struct sb1_2EFC_struct[5]; + /*0x2F9C*/ u8 filler_2F9C[0xA0]; + /*0x303C*/ u8 filler_303C[0x38]; + /*0x3074*/ u8 filler_3074[0x42]; + /*0x30B6*/ u8 filler_30B6; + /*0x30B7*/ u8 filler_30B7[0x59]; + /*0x3110*/ u8 giftRibbons[7]; + /*0x3117*/ u8 filler_311B[0x2D]; + /*0x3144*/ struct Roamer roamer; + /*0x3158*/ u8 filler_3158[0x8]; + /*0x3160*/ struct EnigmaBerry enigmaBerry; // this is actually offset by 0x98 ... + /*0x3690*/ struct RamScript ramScript; + /*0x3A7C*/ u8 filler_3A7C[0x10]; + /*0x3A8C*/ u8 unk3A8C[52]; //pokedex related +} SaveBlock1_RS; + +typedef struct // Don't rely on the commented offsets, they'll be wrong due to elements removed in FR/LG... +{ + /*0x00*/ struct Coords16 pos; + /*0x04*/ struct WarpData location; + /*0x0C*/ struct WarpData warp[4]; + /*0x2C*/ u16 battleMusic; + /*0x2E*/ u8 weather; + /*0x2F*/ u8 filler_2F; + /*0x30*/ u8 flashUsed; + /*0x32*/ u16 mapDataId; +// /*0x34*/ u16 mapView[0x100]; // Not in fr/lg + /*0x234*/ u8 playerPartyCount; + /*0x238*/ struct Pokemon playerParty[6]; + /*0x490*/ u32 money; + /*0x494*/ u16 coins; + /*0x496*/ u16 registeredItem; // registered for use with SELECT button + /*0x498*/ struct ItemSlot pcItems[30]; + /*0x560*/ struct ItemSlot bagPocket_Items[42]; + /*0x5B0*/ struct ItemSlot bagPocket_KeyItems[30]; + /*0x600*/ struct ItemSlot bagPocket_PokeBalls[13]; + /*0x640*/ struct ItemSlot bagPocket_TMHM[58]; + /*0x740*/ struct ItemSlot bagPocket_Berries[43]; +// /*0x7F8*/ struct Pokeblock pokeblocks[40]; // Not in fr/lg + /*0x938*/ u8 unk938[52]; // pokedex related + /*0x96C*/ u8 unk_62C[12]; + /*0x972*/ u8 filler_972[0x6]; + /*0x97A*/ u8 unk_63E[98]; + /*0x9E0*/ struct MapObject mapObjects[16]; + /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64]; + /*0x1220*/ u8 flags[0x120]; + /*0x1340*/ u16 vars[0x100]; + /*0x1540*/ u32 gameStats[64]; // encrypted with saveblock2 xor-key + struct QuestStory questlog[4]; + u8 messages[12][4]; + struct NPCState npc_states[0x10]; + u8 unk_2f10[112]; + struct DaycarePokemon daycare[2]; + u8 unk_3098[56]; + struct Roamer roamer; + u8 unk_30e4[8]; + /*0x3160*/ struct EnigmaBerryFRLGE enigmaBerry; + u8 unk_3120[0x1C0]; // 4 bytes of CRC16, then 444 bytes of unknown. Mystery Gift related. + u8 unk_32E0[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_1" + u8 unk_3430[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_2" + u8 unk_368C[0x9C]; // padding? doesn't seem to be actually used + struct RamScript ramScript; + u8 unk_3A07[17]; + u8 pokemon_flags_2[52]; + u8 rivalName[8]; + u8 unk_3a54[128]; + u8 words[21][10]; + u8 unk_3ba6[570]; +} __attribute__((aligned(1))) SaveBlock1_FRLG; + +typedef struct // Don't rely on the commented offsets, they'll be wrong due to elements changed/added in Emerald... +{ + /*0x00*/ struct Coords16 pos; + /*0x04*/ struct WarpData location; + /*0x0C*/ struct WarpData warp[4]; + /*0x2C*/ u16 battleMusic; + /*0x2E*/ u8 weather; + /*0x2F*/ u8 filler_2F; + /*0x30*/ u8 flashUsed; + /*0x32*/ u16 mapDataId; + /*0x34*/ u16 mapView[0x100]; + /*0x234*/ u8 playerPartyCount; + /*0x238*/ struct Pokemon playerParty[6]; + /*0x490*/ u32 money; + /*0x494*/ u16 coins; + /*0x496*/ u16 registeredItem; // registered for use with SELECT button + /*0x498*/ struct ItemSlot pcItems[50]; + /*0x560*/ struct ItemSlot bagPocket_Items[30]; + /*0x5D8*/ struct ItemSlot bagPocket_KeyItems[30]; + /*0x650*/ struct ItemSlot bagPocket_PokeBalls[16]; + /*0x690*/ struct ItemSlot bagPocket_TMHM[64]; + /*0x790*/ struct ItemSlot bagPocket_Berries[46]; + /*0x7F8*/ struct Pokeblock pokeblocks[40]; // every offset is shifted by 0x50 from here on thanks to changed bag-counts + /*0x938*/ u8 unk938[52]; // pokedex related + /*0x96C*/ u16 berryBlenderRecords[3]; + /*0x972*/ u8 filler_972[0x6]; + /*0x978*/ u16 trainerRematchStepCounter; + /*0x97A*/ u8 trainerRematches[100]; + /*0x9E0*/ struct MapObject mapObjects[16]; + /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64]; + /*0x1220*/ u8 flags[0x12C]; + /*0x1340*/ u16 vars[0x100]; // offsets shifted by 0x5C from here on thanks to added flags + /*0x1540*/ u32 gameStats[64]; // encrypted with saveblock2 xor-key + /*0x1608*/ struct BerryTree berryTrees[128]; // offsets shifted by 0x94 from here on thanks to added 14 gamestats + /*0x1A08*/ struct SecretBaseRecord secretBases[20]; + /*0x2688*/ u8 playerRoomDecor[12]; + /*0x2694*/ u8 playerRoomDecorPos[12]; + /*0x26A0*/ u8 decorDesk[10]; + /*0x26AA*/ u8 decorChair[10]; + /*0x26B4*/ u8 decorPlant[10]; + /*0x26BE*/ u8 decorOrnament[30]; + /*0x26DC*/ u8 decorMat[30]; + /*0x26FA*/ u8 decorPoster[10]; + /*0x2704*/ u8 decorDoll[40]; + /*0x272C*/ u8 decorCushion[10]; + // /*0x2736*/ u8 padding_2736[2]; + /*0x2738*/ TVShow tvShows[24]; + /*0x2A98*/ u8 filler_2A98[0x64]; + /*0x2AFC*/ u16 outbreakPokemonSpecies; // offset by 0x94 + /*0x2AFE*/ u8 outbreakLocationMapNum; + /*0x2AFF*/ u8 outbreakLocationMapGroup; + /*0x2B00*/ u8 outbreakPokemonLevel; + /*0x2B01*/ u8 outbreakUnk1; + /*0x2B02*/ u16 outbreakUnk2; + /*0x2B04*/ u16 outbreakPokemonMoves[4]; + /*0x2B0C*/ u8 outbreakUnk4; + /*0x2B0D*/ u8 outbreakPokemonProbability; + /*0x2B0E*/ u16 outbreakUnk5; + /*0x2B10*/ u8 filler_2B0E[0xC]; + /*0x2B1C*/ u16 unk2B1C[4]; + /*0x2B24*/ u8 filler_2B24[0x28]; + /*0x2B4C*/ struct MailStruct mail[16]; // offset by 0x94 + /*0x2D8C*/ u8 filler_2D8C[0x8]; + /*0x2D94*/ OldMan oldMan; + /*0x2DC0*/ u8 unk_2DC0[0x14]; + /*0x2DD4*/ struct EasyChatPair easyChatPairs[5]; //Dewford trend [0] and some other stuff + // /*0x2DFC*/ u8 filler_2DFC[0x100]; + /*0x2EFC*/ struct SB1_2EFC_Struct sb1_2EFC_struct[12]; + u8 unk_3010[0x198]; // no idea if any of this is actually used. + /*0x3110*/ u8 giftRibbons[7]; + /*0x3117*/ u8 filler_311B[0x2D]; + /*0x3144*/ struct Roamer roamer; + /*0x3158*/ u8 filler_3158[0x8]; + /*0x3160*/ struct EnigmaBerryFRLGE enigmaBerry; + u8 unk_322C[0x1C0]; // 4 bytes of CRC16, then 444 bytes of unknown. Mystery Gift related. + u8 unk_33EC[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_1" + u8 unk_353C[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_2" + u8 unk_368C[0x9C]; // padding? doesn't seem to be actually used + /*0x3690*/ struct RamScript ramScript; + /*0x3A7C*/ u8 filler_3A7C[0x10]; + /*0x3A8C*/ u8 unk3A8C[52]; //pokedex related +} SaveBlock1_E; + +// --- + +struct SaveBlock2_Sub +{ + /*0x0000, 0x00A8*/ u8 filler_000[0x4AE]; + /*0x04AE, 0x0556*/ u8 var_4AE; + /*0x04AF, 0x0557*/ u8 var_4AF; + /*0x04B0, 0x0558*/ u16 var_4B0; + /*0x04B2, 0x055A*/ u16 var_4B2; + /*0x04B4, 0x055C*/ u16 var_4B4; + /*0x04B6, 0x055E*/ u16 var_4B6; + /*0x04B8, 0x0560*/ u8 filler_4B8[0x10]; + /*0x04C8, 0x0570*/ u16 var_4C8; + /*0x04CA, 0x0572*/ u16 var_4CA; + /*0x04CC, 0x0574*/ u8 filler_4CC[0x31C]; +}; + +typedef struct +{ + /*0x00*/ u8 playerName[8]; + /*0x08*/ u8 playerGender; // MALE, FEMALE + /*0x09*/ u8 specialSaveWarp; + /*0x0A*/ u8 playerTrainerId[4]; + /*0x0E*/ u16 playTimeHours; + /*0x10*/ u8 playTimeMinutes; + /*0x11*/ u8 playTimeSeconds; + /*0x12*/ u8 playTimeVBlanks; + /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A] + /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST] + u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes + u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO] + u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET] + u16 optionsBattleSceneOff:1; // whether battle animations are disabled + u16 regionMapZoom:1; // whether the map is zoomed in + /*0x18*/ struct Pokedex pokedex; + /*0x90*/ u8 filler_90[0x8]; + /*0x98*/ struct Time localTimeOffset; + /*0xA0*/ struct Time lastBerryTreeUpdate; + /*0xA8*/ struct SaveBlock2_Sub filler_A8; +} SaveBlock2_RS; + +typedef struct +{ + /*0x00*/ u8 playerName[8]; + /*0x08*/ u8 playerGender; // MALE, FEMALE + /*0x09*/ u8 specialSaveWarp; + /*0x0A*/ u8 playerTrainerId[4]; + /*0x0E*/ u16 playTimeHours; + /*0x10*/ u8 playTimeMinutes; + /*0x11*/ u8 playTimeSeconds; + /*0x12*/ u8 playTimeVBlanks; + /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A] + /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST] + u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes + u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO] + u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET] + u16 optionsBattleSceneOff:1; // whether battle animations are disabled + u16 regionMapZoom:1; // whether the map is zoomed in + /*0x18*/ struct Pokedex pokedex; + /*0x90*/ u8 filler_90[0x8]; + /*0x98*/ struct Time localTimeOffset; + /*0xA0*/ struct Time lastBerryTreeUpdate; + /*0xA8*/ struct SaveBlock2_Sub filler_A8; + /*0x890*/ u8 unk_890[8]; + /*0x898*/ u8 mapdata[0x258]; + /*0xaf0*/ u16 field_af0; + /*0xaf2*/ u16 field_af2; + /*0xaf4*/ u16 field_af4; + /*0xaf6*/ u16 field_af6; + /*0xaf8*/ u8 unk_af8[0x428]; + /*0xf20*/ u32 xor_key; +} SaveBlock2_FRLG; + +typedef struct +{ + /*0x00*/ u8 playerName[8]; + /*0x08*/ u8 playerGender; // MALE, FEMALE + /*0x09*/ u8 specialSaveWarp; + /*0x0A*/ u8 playerTrainerId[4]; + /*0x0E*/ u16 playTimeHours; + /*0x10*/ u8 playTimeMinutes; + /*0x11*/ u8 playTimeSeconds; + /*0x12*/ u8 playTimeVBlanks; + /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A] + /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST] + u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes + u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO] + u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET] + u16 optionsBattleSceneOff:1; // whether battle animations are disabled + u16 regionMapZoom:1; // whether the map is zoomed in + /*0x18*/ struct Pokedex pokedex; + /*0x90*/ u8 filler_90[0x8]; + /*0x98*/ struct Time localTimeOffset; + /*0xA0*/ struct Time lastBerryTreeUpdate; + /*0xA8*/ u32 xor_key; + /*0xAC*/ struct SaveBlock2_Sub filler_A8; +} SaveBlock2_E; + +typedef union { + SaveBlock1_RS rs; + SaveBlock1_FRLG frlg; + SaveBlock1_E e; +} SaveBlock1, *pSaveBlock1; + +typedef union { + SaveBlock2_RS rs; + SaveBlock2_FRLG frlg; + SaveBlock2_E e; +} SaveBlock2, *pSaveBlock2; + +typedef struct PokemonStorage SaveBlock3, *pSaveBlock3; \ No newline at end of file diff --git a/gba/source/savestructs.h b/gba/source/savestructs.h new file mode 100644 index 0000000..2bf4d4d --- /dev/null +++ b/gba/source/savestructs.h @@ -0,0 +1,793 @@ +/* + * Example Gen3-multiboot payload by slipstream/RoL 2017. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + * saveblocks.h: describes structures used by saveblocks for all of Gen 3 + */ + +// Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity + +#define POKEMON_NAME_LENGTH 10 +#define OT_NAME_LENGTH 7 +#define TILE_SIZE_4BPP 32 + +struct Coords16 +{ + s16 x; + s16 y; +}; + +struct UCoords16 +{ + u16 x; + u16 y; +}; + +struct SecretBaseRecord +{ + u8 sbr_field_0; // ID? + u8 sbr_field_1_0:4; + u8 gender:1; + u8 sbr_field_1_5:1; + u8 sbr_field_2[7]; // 0xFF bytes? + u8 trainerId[4]; // byte 0 is used for determining trainer class + u16 sbr_field_e; + u8 sbr_field_10; + u8 sbr_field_11; + u8 decorations[16]; + u8 sbr_field_22[16]; + u32 partyPersonality[6]; + u16 partyMoves[6 * 4]; + u16 partySpecies[6]; + u16 partyHeldItems[6]; + u8 partyLevels[6]; + u8 partyEVs[6]; +}; + +typedef void (*TilesetCB)(void); + +struct Tileset +{ + u8 isCompressed; + u8 isSecondary; + void *tiles; + void *palettes; + void *metatiles; + void *metatileAttributes; + TilesetCB callback; +}; + +struct MapData +{ + s32 width; + s32 height; + u16 *border; + u16 *map; + struct Tileset *primaryTileset; + struct Tileset *secondaryTileset; +}; + +struct MapObjectTemplate +{ + /*0x00*/ u8 localId; + /*0x01*/ u8 graphicsId; + /*0x02*/ u8 unk2; + /*0x04*/ s16 x; + /*0x06*/ s16 y; + /*0x08*/ u8 elevation; + /*0x09*/ u8 movementType; + /*0x0A*/ u8 unkA_0:4; + u8 unkA_4:4; + ///*0x0B*/ u8 fillerB[1]; + /*0x0C*/ u16 unkC; + /*0x0E*/ u16 unkE; + /*0x10*/ u8 *script; + /*0x14*/ u16 flagId; + /*0x16*/ u8 filler_16[2]; +}; /*size = 0x18*/ + +struct WarpEvent +{ + s16 x, y; + s8 warpId; + u8 mapGroup; + u8 mapNum; + u8 unk7; +}; + +struct CoordEvent +{ + s16 x, y; + u8 unk4; + u8 filler_5; + u16 trigger; + u16 index; + u8 filler_A[0x2]; + u8 *script; +}; + +struct BgEvent +{ + s16 x, y; + u8 unk4; + u8 kind; + s16 filler_6; + u8 *script; +}; + +struct MapEvents +{ + u8 mapObjectCount; + u8 warpCount; + u8 coordEventCount; + u8 bgEventCount; + + struct MapObjectTemplate *mapObjects; + struct WarpEvent *warps; + struct CoordEvent *coordEvents; + struct BgEvent *bgEvents; +}; + +struct MapConnection +{ + u8 direction; + u32 offset; + u8 mapGroup; + u8 mapNum; +}; + +struct MapConnections +{ + s32 count; + struct MapConnection *connections; +}; + +struct MapHeader +{ + struct MapData *mapData; + struct MapEvents *events; + u8 *mapScripts; + struct MapConnections *connections; + u16 music; + u16 mapDataId; + u8 name; + u8 cave; + u8 weather; + /* 0x17 */ u8 mapType; + u8 filler_18; + u8 escapeRope; + u8 flags; + u8 battleType; +}; + +struct MapObject +{ + /*0x00*/ u32 active:1; + u32 mapobj_bit_1:1; + u32 mapobj_bit_2:1; + u32 mapobj_bit_3:1; + u32 mapobj_bit_4:1; + u32 mapobj_bit_5:1; + u32 mapobj_bit_6:1; + u32 mapobj_bit_7:1; + /*0x01*/ u32 mapobj_bit_8:1; + u32 mapobj_bit_9:1; + u32 mapobj_bit_10:1; + u32 mapobj_bit_11:1; + u32 mapobj_bit_12:1; + u32 mapobj_bit_13:1; + u32 mapobj_bit_14:1; + u32 mapobj_bit_15:1; + /*0x02*/ u32 mapobj_bit_16:1; + u32 mapobj_bit_17:1; + u32 mapobj_bit_18:1; + u32 mapobj_bit_19:1; + u32 mapobj_bit_20:1; + u32 mapobj_bit_21:1; + u32 mapobj_bit_22:1; + u32 mapobj_bit_23:1; + /*0x03*/ u32 mapobj_bit_24:1; + u32 mapobj_bit_25:1; + u32 mapobj_bit_26:1; + u32 mapobj_bit_27:1; + u32 mapobj_bit_28:1; + u32 mapobj_bit_29:1; + u32 mapobj_bit_30:1; + u32 mapobj_bit_31:1; + /*0x04*/ u8 spriteId; + /*0x05*/ u8 graphicsId; + /*0x06*/ u8 animPattern; + /*0x07*/ u8 trainerType; + /*0x08*/ u8 localId; + /*0x09*/ u8 mapNum; + /*0x0A*/ u8 mapGroup; + /*0x0B*/ u8 mapobj_unk_0B_0:4; + u8 elevation:4; + /*0x0C*/ struct Coords16 coords1; + /*0x10*/ struct Coords16 coords2; + /*0x14*/ struct Coords16 coords3; + /*0x18*/ u8 mapobj_unk_18:4; //current direction? + /*0x18*/ u8 placeholder18:4; + /*0x19*/ u8 mapobj_unk_19; + /*0x1A*/ u8 mapobj_unk_1A; + /*0x1B*/ u8 mapobj_unk_1B; + /*0x1C*/ u8 mapobj_unk_1C; + /*0x1D*/ u8 trainerRange_berryTreeId; + /*0x1E*/ u8 mapobj_unk_1E; + /*0x1F*/ u8 mapobj_unk_1F; + /*0x20*/ u8 mapobj_unk_20; + /*0x21*/ u8 mapobj_unk_21; + /*0x22*/ u8 animId; + /*size = 0x24*/ +}; + +struct Berry +{ + const u8 name[7]; + u8 firmness; + u16 size; + u8 maxYield; + u8 minYield; + const u8 *description1; + const u8 *description2; + u8 stageDuration; + u8 spicy; + u8 dry; + u8 sweet; + u8 bitter; + u8 sour; + u8 smoothness; +}; + +struct EnigmaBerry +{ + struct Berry berry; + u8 pic[(6 * 6) * TILE_SIZE_4BPP]; + u16 palette[16]; + u8 description1[45]; + u8 description2[45]; + u8 itemEffect[18]; + u8 holdEffect; + u8 holdEffectParam; + u32 checksum; +}; + +struct BattleEnigmaBerry +{ + u8 name[7]; + u8 holdEffect; + u8 itemEffect[18]; + u8 holdEffectParam; +}; + +struct EnigmaBerryFRLGE { + struct Berry berry; // 0x00 + u8 itemEffect[18]; // 0x1C + u8 holdEffect; // 0x2E + u8 holdEffectParam; // 0x2F + u32 checksum; // 0x30 +}; + +struct __attribute__((aligned(4))) BerryTree +{ + u8 berry; + u8 stage:7; + u8 growthSparkle:1; + u16 secondsUntilNextStage; + u8 berryYield; + u8 regrowthCount:4; + u8 watered1:1; + u8 watered2:1; + u8 watered3:1; + u8 watered4:1; +}; + +struct PokemonSubstruct0 +{ + u16 species; + u16 heldItem; + u32 experience; + u8 ppBonuses; + u8 friendship; +}; + +struct PokemonSubstruct1 +{ + u16 moves[4]; + u8 pp[4]; +}; + +struct PokemonSubstruct2 +{ + u8 hpEV; + u8 attackEV; + u8 defenseEV; + u8 speedEV; + u8 spAttackEV; + u8 spDefenseEV; + u8 cool; + u8 beauty; + u8 cute; + u8 smart; + u8 tough; + u8 sheen; +}; + +struct PokemonSubstruct3 +{ + /* 0x00 */ u8 pokerus; + /* 0x01 */ u8 metLocation; + + /* 0x02 */ u16 metLevel:7; + /* 0x02 */ u16 metGame:4; + /* 0x03 */ u16 pokeball:4; + /* 0x03 */ u16 otGender:1; + + /* 0x04 */ u32 hpIV:5; + /* 0x04 */ u32 attackIV:5; + /* 0x05 */ u32 defenseIV:5; + /* 0x05 */ u32 speedIV:5; + /* 0x05 */ u32 spAttackIV:5; + /* 0x06 */ u32 spDefenseIV:5; + /* 0x07 */ u32 isEgg:1; + /* 0x07 */ u32 altAbility:1; + + /* 0x08 */ u32 coolRibbon:3; + /* 0x08 */ u32 beautyRibbon:3; + /* 0x08 */ u32 cuteRibbon:3; + /* 0x09 */ u32 smartRibbon:3; + /* 0x09 */ u32 toughRibbon:3; + /* 0x09 */ u32 championRibbon:1; + /* 0x0A */ u32 winningRibbon:1; + /* 0x0A */ u32 victoryRibbon:1; + /* 0x0A */ u32 artistRibbon:1; + /* 0x0A */ u32 effortRibbon:1; + /* 0x0A */ u32 giftRibbon1:1; + /* 0x0A */ u32 giftRibbon2:1; + /* 0x0A */ u32 giftRibbon3:1; + /* 0x0A */ u32 giftRibbon4:1; + /* 0x0B */ u32 giftRibbon5:1; + /* 0x0B */ u32 giftRibbon6:1; + /* 0x0B */ u32 giftRibbon7:1; + /* 0x0B */ u32 fatefulEncounter:5; // unused in Ruby/Sapphire, but the high bit must be set for Mew/Deoxys to obey in FR/LG/Emerald +}; + +union PokemonSubstruct +{ + struct PokemonSubstruct0 type0; + struct PokemonSubstruct1 type1; + struct PokemonSubstruct2 type2; + struct PokemonSubstruct3 type3; + u16 raw[6]; +}; + +struct BoxPokemon +{ + u32 personality; + u32 otId; + u8 nickname[POKEMON_NAME_LENGTH]; + u8 language; + u8 isBadEgg:1; + u8 hasSpecies:1; + u8 isEgg:1; + u8 unused:5; + u8 otName[OT_NAME_LENGTH]; + u8 markings; + u16 checksum; + u16 unknown; + + union + { + u32 raw[12]; + union PokemonSubstruct substructs[4]; + } secure; +}; + +struct Pokemon +{ + struct BoxPokemon box; + u32 status; + u8 level; + u8 pokerus; + u16 hp; + u16 maxHP; + u16 attack; + u16 defense; + u16 speed; + u16 spAttack; + u16 spDefense; +}; + +struct UnknownPokemonStruct +{ + u16 species; + u16 heldItem; + u16 moves[4]; + u8 level; + u8 ppBonuses; + u8 hpEV; + u8 attackEV; + u8 defenseEV; + u8 speedEV; + u8 spAttackEV; + u8 spDefenseEV; + u32 otId; + u32 hpIV:5; + u32 attackIV:5; + u32 defenseIV:5; + u32 speedIV:5; + u32 spAttackIV:5; + u32 spDefenseIV:5; + u32 gap:1; + u32 altAbility:1; + u32 personality; + u8 nickname[POKEMON_NAME_LENGTH + 1]; + u8 friendship; +}; + +struct BattlePokemon +{ + /* 0x00 */ u16 species; + /* 0x02 */ u16 attack; + /* 0x04 */ u16 defense; + /* 0x06 */ u16 speed; + /* 0x08 */ u16 spAttack; + /* 0x0A */ u16 spDefense; + /* 0x0C */ u16 moves[4]; + /* 0x14 */ u32 hpIV:5; + /* 0x14 */ u32 attackIV:5; + /* 0x15 */ u32 defenseIV:5; + /* 0x15 */ u32 speedIV:5; + /* 0x16 */ u32 spAttackIV:5; + /* 0x17 */ u32 spDefenseIV:5; + /* 0x17 */ u32 isEgg:1; + /* 0x17 */ u32 altAbility:1; + /* 0x18 */ s8 statStages[8]; + /* 0x20 */ u8 ability; + /* 0x21 */ u8 type1; + /* 0x22 */ u8 type2; + /* 0x23 */ u8 unknown; + /* 0x24 */ u8 pp[4]; + /* 0x28 */ u16 hp; + /* 0x2A */ u8 level; + /* 0x2B */ u8 friendship; + /* 0x2C */ u16 maxHP; + /* 0x2E */ u16 item; + /* 0x30 */ u8 nickname[POKEMON_NAME_LENGTH + 1]; + /* 0x3B */ u8 ppBonuses; + /* 0x3C */ u8 otName[8]; + /* 0x44 */ u32 experience; + /* 0x48 */ u32 personality; + /* 0x4C */ u32 status1; + /* 0x50 */ u32 status2; + /* 0x54 */ u32 otId; +}; + +struct BaseStats +{ + /* 0x00 */ u8 baseHP; + /* 0x01 */ u8 baseAttack; + /* 0x02 */ u8 baseDefense; + /* 0x03 */ u8 baseSpeed; + /* 0x04 */ u8 baseSpAttack; + /* 0x05 */ u8 baseSpDefense; + /* 0x06 */ u8 type1; + /* 0x07 */ u8 type2; + /* 0x08 */ u8 catchRate; + /* 0x09 */ u8 expYield; + /* 0x0A */ u16 evYield_HP:2; + /* 0x0A */ u16 evYield_Attack:2; + /* 0x0A */ u16 evYield_Defense:2; + /* 0x0A */ u16 evYield_Speed:2; + /* 0x0B */ u16 evYield_SpAttack:2; + /* 0x0B */ u16 evYield_SpDefense:2; + /* 0x0C */ u16 item1; + /* 0x0E */ u16 item2; + /* 0x10 */ u8 genderRatio; + /* 0x11 */ u8 eggCycles; + /* 0x12 */ u8 friendship; + /* 0x13 */ u8 growthRate; + /* 0x14 */ u8 eggGroup1; + /* 0x15 */ u8 eggGroup2; + /* 0x16 */ u8 ability1; + /* 0x17 */ u8 ability2; + /* 0x18 */ u8 safariZoneFleeRate; + /* 0x19 */ u8 bodyColor; +}; + +struct BattleMove +{ + u8 effect; + u8 power; + u8 type; + u8 accuracy; + u8 pp; + u8 secondaryEffectChance; + u8 target; + u8 priority; + u32 flags; +}; + +struct PokemonStorage +{ + /* 0x00 */ u8 currentBox; + /* 0x01 */ struct BoxPokemon boxes[14][30]; + u8 boxNames[14][9]; + u8 boxBackground[14]; +}; + +struct WarpData +{ + s8 mapGroup; + s8 mapNum; + s8 warpId; + s16 x, y; +}; + +struct ItemSlot +{ + u16 itemId; + u16 quantity; +}; + +struct __attribute__((aligned(2))) Pokeblock +{ + u8 color; + u8 spicy; + u8 dry; + u8 sweet; + u8 bitter; + u8 sour; + u8 feel; +}; + +struct Roamer +{ + /*0x00*/ u32 ivs; + /*0x04*/ u32 personality; + /*0x08*/ u16 species; + /*0x0A*/ u16 hp; + /*0x0C*/ u8 level; + /*0x0D*/ u8 status; + /*0x0E*/ u8 cool; + /*0x0F*/ u8 beauty; + /*0x10*/ u8 cute; + /*0x11*/ u8 smart; + /*0x12*/ u8 tough; + /*0x13*/ u8 active; +}; + +struct RamScriptData +{ + u8 magic; + u8 mapGroup; + u8 mapNum; + u8 objectId; + u8 script[995]; +} __attribute__((aligned(1),packed)); + +struct RamScript +{ + u32 checksum; + struct RamScriptData data; +} __attribute__((aligned(1),packed)); + +struct SB1_2EFC_Struct +{ + u8 unknown[0x20]; +}; + +struct EasyChatPair +{ + u16 unk0_0:7; + u16 unk0_7:7; + u16 unk1_6:1; + u16 unk2; + u16 words[2]; +}; /*size = 0x8*/ + +struct TVShowCommon { + /*0x00*/ u8 var00; + /*0x01*/ u8 var01; +}; + +struct TVShowFanClubLetter { + /*0x00*/ u8 var00; + /*0x01*/ u8 var01; + /*0x02*/ u16 species; + u8 pad04[12]; + /*0x10*/ u8 playerName[8]; + /*0x18*/ u8 var18; +}; + +struct TVShowRecentHappenings { + /*0x00*/ u8 var00; + /*0x01*/ u8 var01; + /*0x02*/ u16 var02; + u8 pad04[12]; + /*0x10*/ u8 var10[8]; + /*0x18*/ u8 var18; + u8 pad19[10]; +}; + +struct TVShowFanclubOpinions { + /*0x00*/ u8 var00; + /*0x01*/ u8 var01; + /*0x02*/ u16 var02; + /*0x04*/ u8 var04A:4; + u8 var04B:4; + /*0x04*/ u8 var05[8]; + /*0x0D*/ u8 var0D; + /*0x0E*/ u8 var0E; + /*0x0F*/ u8 var0F; + /*0x10*/ u8 var10[8]; +}; + +struct TVShowNameRaterShow { + /*0x00*/ u8 var00; + /*0x01*/ u8 var01; + /*0x02*/ u16 species; + /*0x04*/ u8 pokemonName[11]; + /*0x0F*/ u8 trainerName[11]; + /*0x1A*/ u8 random; + /*0x1B*/ u8 random2; + /*0x1C*/ u16 var1C; + /*0x1E*/ u8 language; + /*0x1F*/ u8 var1F; +}; + +struct TVShowMassOutbreak { + /*0x00*/ u8 var00; + /*0x01*/ u8 var01; + /*0x02*/ u8 var02; + /*0x03*/ u8 var03; + /*0x04*/ u16 moves[4]; + /*0x0C*/ u16 species; + /*0x0E*/ u16 var0E; + /*0x10*/ u8 locationMapNum; + /*0x11*/ u8 locationMapGroup; + /*0x12*/ u8 var12; + /*0x13*/ u8 probability; + /*0x14*/ u8 level; + /*0x15*/ u8 var15; + /*0x16*/ u16 var16; + /*0x18*/ u8 var18; + u8 pad19[11]; +}; + +typedef union TVShow { + struct TVShowCommon common; + struct TVShowFanClubLetter fanclubLetter; + struct TVShowRecentHappenings recentHappenings; + struct TVShowFanclubOpinions fanclubOpinions; + struct TVShowNameRaterShow nameRaterShow; + struct TVShowMassOutbreak massOutbreak; +} TVShow; + +struct __attribute__((aligned(4))) MailStruct +{ + /*0x00*/ u16 words[9]; + /*0x12*/ u8 playerName[8]; + /*0x1A*/ u8 trainerId[4]; + /*0x1E*/ u16 species; + /*0x20*/ u16 itemId; +}; + +struct UnkMauvilleOldManStruct +{ + u8 unk_2D94; + u8 unk_2D95; + /*0x2D96*/ u16 mauvilleOldMan_ecArray[6]; + /*0x2DA2*/ u16 mauvilleOldMan_ecArray2[6]; + /*0x2DAE*/ u8 playerName[8]; + /*0x2DB6*/ u8 filler_2DB6[0x3]; + /*0x2DB9*/ u8 playerTrainerId[4]; + u8 unk_2DBD; + /* size = 0x2C */ +}; + +struct UnkMauvilleOldManStruct2 +{ + u8 filler0; + u8 unk1; + u8 unk2; + u16 mauvilleOldMan_ecArray[10]; + u16 mauvilleOldMan_ecArray2[6]; + u8 fillerF[0x2]; + /* size = 0x2C */ +}; + +typedef union OldMan { + struct UnkMauvilleOldManStruct oldMan1; + struct UnkMauvilleOldManStruct2 oldMan2; +} OldMan; + +struct QuestStoryNPC { + u16 bitfield; + u8 direction; + u8 height; + u8 type_id; + u8 running_behaviour_or_picture_id; + u8 is_trainer; + u8 local_id; + u8 local_mapnumber; + u8 local_mapbank; + u16 x; + u16 y; + u8 sight_distance; + u8 role_from; + u8 unknown_decrement_on_step; + u8 unk_11; + u16 padding_12; +}; + +struct QuestStory { + u8 active; + u8 bank; + u8 map; + u8 warpId; + u16 x; + u16 y; + struct QuestStoryNPC npc[0x10]; + u8 unk_148[0x51f]; +}; + +struct NPCState { + u8 bitfield; + u8 obj_anim_and_vis_control; + u8 unk_2; + u8 unk_3; + u8 oamid; + u8 type_id; + u8 running_behaviour_or_picture_id; + u8 is_trainer; + u8 local_id; + u8 local_mapnumber; + u8 local_mapbank; + u8 height; + struct Coords16 stay_around; + struct Coords16 to; + struct Coords16 from; + u8 direction; + u8 movement_area; + u8 objid_surfing; + u8 objid_1B; + u8 idx_movement_behaviour; + u8 sight_distance; + u8 role_to; + u8 role_from; + u8 unk_20; + u8 unknown_decrement_on_step; + u8 unk_22; + u8 unk_23; +}; + +struct DaycarePokemon { + struct BoxPokemon pokemon; + u8 unk_50[56]; + u32 steps; +}; + + +struct Time +{ + /*0x00*/ s16 days; + /*0x02*/ s8 hours; + /*0x03*/ s8 minutes; + /*0x04*/ s8 seconds; +}; + +struct Pokedex +{ + /*0x00*/ u8 order; + /*0x01*/ u8 unknown1; + /*0x02*/ u8 nationalMagic; // must equal 0xDA in order to have National mode + /*0x03*/ u8 unknown2; + /*0x04*/ u32 unownPersonality; // set when you first see Unown + /*0x08*/ u32 spindaPersonality; // set when you first see Spinda + /*0x0C*/ u32 unknown3; + /*0x10*/ u8 owned[52]; + /*0x44*/ u8 seen[52]; +}; \ No newline at end of file -- cgit 1.4.1