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/libpayload.c | 312 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 gba/source/libpayload.c (limited to 'gba/source/libpayload.c') 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 -- cgit 1.4.1