diff options
Diffstat (limited to 'arm9/src')
-rw-r--r-- | arm9/src/pokemon.c | 208 |
1 files changed, 204 insertions, 4 deletions
diff --git a/arm9/src/pokemon.c b/arm9/src/pokemon.c index 60381e75..c59cfe4e 100644 --- a/arm9/src/pokemon.c +++ b/arm9/src/pokemon.c @@ -3,12 +3,15 @@ #include "pokemon.h" #include "heap.h" #include "MI_memory.h" +#include "math_util.h" #pragma thumb on void MonEncryptSegment(void * datap, u32 size, u32 key, ...); void MonDecryptSegment(void * datap, u32 size, u32 key, ...); u16 MonEncryptionLCRNG(u32 * seed); +u16 CalcMonChecksum(void * datap, u32 size); +void InitBoxMonMoveset(struct BoxPokemon * boxmon); #define ENCRY_ARGS_PTY(mon) &(mon)->party, sizeof((mon)->party), (mon)->box.pid #define ENCRY_ARGS_BOX(boxmon) &(boxmon)->substructs, sizeof((boxmon)->substructs), (boxmon)->checksum @@ -16,6 +19,13 @@ u16 MonEncryptionLCRNG(u32 * seed); #define ENCRYPT_BOX(boxmon) MonEncryptSegment(ENCRY_ARGS_BOX(boxmon)) #define DECRYPT_PTY(mon) MonDecryptSegment(ENCRY_ARGS_PTY(mon)) #define DECRYPT_BOX(boxmon) MonDecryptSegment(ENCRY_ARGS_BOX(boxmon)) +#define SHINY_CHECK(otid, pid) (( \ + ((((otid) & 0xFFFF0000u) >> 16u)) ^ \ + (((otid) & 0xFFFFu)) ^ \ + ((((pid) & 0xFFFF0000u) >> 16u))^ \ + (((pid) & 0xFFFFu))) \ + < 8u) +#define CALC_UNOWN_LETTER(pid) ((u32)((((pid) & 0x3000000) >> 18) | (((pid) & 0x30000) >> 12) | (((pid) & 0x300) >> 6) | (((pid) & 0x3) >> 0)) % 28u) void ZeroMonData(struct Pokemon * pokemon) { @@ -46,14 +56,204 @@ BOOL TryDecryptMon(struct Pokemon * mon) { BOOL ret = FALSE; - if (!mon->box.no_encrypt) + if (!mon->box.party_lock) { ret = TRUE; - GF_ASSERT(!mon->box.control_4_1); - mon->box.no_encrypt = TRUE; - mon->box.control_4_1 = TRUE; + GF_ASSERT(!mon->box.box_lock); + mon->box.party_lock = TRUE; + mon->box.box_lock = TRUE; DECRYPT_PTY(mon); DECRYPT_BOX(&mon->box); } return ret; } + +BOOL TryEncryptMon(struct Pokemon * mon, BOOL decrypt_result) +{ + BOOL ret = FALSE; + if (mon->box.party_lock == TRUE && decrypt_result == TRUE) + { + ret = TRUE; + mon->box.party_lock = FALSE; + mon->box.box_lock = FALSE; + ENCRYPT_PTY(mon); + mon->box.checksum = CalcMonChecksum(&mon->box.substructs, sizeof(mon->box.substructs)); + ENCRYPT_BOX(&mon->box); + } + return ret; +} + +BOOL TryDecryptBoxMon(struct BoxPokemon * mon) +{ + BOOL ret = FALSE; + + if (!mon->box_lock) + { + ret = TRUE; + mon->box_lock = TRUE; + DECRYPT_BOX(mon); + } + return ret; +} + +BOOL TryEncryptBoxMon(struct BoxPokemon * mon, BOOL decrypt_result) +{ + BOOL ret = FALSE; + if (mon->box_lock == TRUE && decrypt_result == TRUE) + { + ret = TRUE; + mon->box_lock = FALSE; + mon->checksum = CalcMonChecksum(&mon->substructs, sizeof(mon->substructs)); + ENCRYPT_BOX(mon); + } + return ret; +} + +void CreateMon(struct Pokemon * pokemon, int species, int level, int fixedIV, int hasFixedPersonality, int fixedPersonality, int otIdType, int fixedOtId, ...) +{ + struct SealStruct * seal; + u32 capsule; + u8 seal_coords[0x18]; + ZeroMonData(pokemon); + CreateBoxMon(&pokemon->box, species, level, fixedIV, hasFixedPersonality, fixedPersonality, otIdType, fixedOtId); + // Not your average encryption call + MonEncryptSegment(&pokemon->party, sizeof(pokemon->party), 0); + ENCRYPT_PTY(pokemon); + SetMonDataEncrypted(pokemon, MON_DATA_LEVEL, &level); + seal = CreateNewSealsObject(0); + SetMonDataEncrypted(pokemon, MON_DATA_SEAL_STRUCT, seal); + FreeToHeap(seal); + capsule = 0; + SetMonDataEncrypted(pokemon, MON_DATA_CAPSULE, &capsule); + MIi_CpuClearFast(0, seal_coords, sizeof(seal_coords)); + SetMonDataEncrypted(pokemon, MON_DATA_SEAL_COORDS, seal_coords); + CalcMonStats(pokemon); +} + +void CreateBoxMon(struct BoxPokemon * boxPokemon, int species, int level, int fixedIV, int hasFixedPersonality, int fixedPersonality, int otIdType, int fixedOtId, ...) +{ + BOOL decry; + u32 exp; + u32 iv; + ZeroBoxMonData(boxPokemon); + decry = TryDecryptBoxMon(boxPokemon); + if (hasFixedPersonality == 0) + { + fixedPersonality = (rand_LC() | (rand_LC() << 16)); + } + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_PERSONALITY, &fixedPersonality); + if (otIdType == 2) + { + do + { + fixedOtId = (rand_LC() | (rand_LC() << 16)); + } while (SHINY_CHECK(fixedOtId, fixedPersonality)); + } + else if (otIdType != 1) + fixedOtId = 0; + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_OTID, &fixedOtId); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_GAME_LANGUAGE, &gGameLanguage); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_SPECIES, &species); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_SPECIES_NAME, NULL); + exp = GetMonExpBySpeciesAndLevel(species, level); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_EXPERIENCE, &exp); + exp = GetMonBaseStat(species, BASE_FRIENDSHIP); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_FRIENDSHIP, &exp); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_MET_LEVEL, &level); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_GAME_VERSION, &gGameVersion); + exp = 4; + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_POKEBALL, &exp); + if (fixedIV < 0x20) + { + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_HP_IV, &fixedIV); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_ATK_IV, &fixedIV); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_DEF_IV, &fixedIV); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_SPEED_IV, &fixedIV); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_SPATK_IV, &fixedIV); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_SPDEF_IV, &fixedIV); + } + else + { + exp = rand_LC(); + iv = exp & 0x1F; + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_HP_IV, &iv); + iv = (exp & 0x3E0) >> 5; + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_ATK_IV, &iv); + iv = (exp & 0x7C00) >> 10; + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_DEF_IV, &iv); + exp = rand_LC(); + iv = exp & 0x1F; + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_SPEED_IV, &iv); + iv = (exp & 0x3E0) >> 5; + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_SPATK_IV, &iv); + iv = (exp & 0x7C00) >> 10; + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_SPDEF_IV, &iv); + } + exp = GetMonBaseStat(species, BASE_ABILITY_1); + iv = GetMonBaseStat(species, BASE_ABILITY_2); + if (iv != 0) + { + if (fixedPersonality & 1) + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_ABILITY, &iv); + else + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_ABILITY, &exp); + } + else + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_ABILITY, &exp); + exp = GetBoxMonGenderEncrypted(boxPokemon); + SetBoxMonDataEncrypted(boxPokemon, MON_DATA_GENDER, &exp); + InitBoxMonMoveset(boxPokemon); + TryEncryptBoxMon(boxPokemon, decry); +} + +void CreateMonWithNature(struct Pokemon * pokemon, u16 species, u8 level, u8 fixedIv, u8 nature) +{ + u32 personality; + do + { + personality = (u32)(rand_LC() | (rand_LC() << 16)); + } while (nature != GetNatureFromPersonality(personality)); + CreateMon(pokemon, (int)species, (int)level, (int)fixedIv, 1, (int)personality, (int)0, (int)0); +} + +// FIXME: stack storage of pokemon, fixedIv swapped +void CreateMonWithGenderNatureLetter(struct Pokemon * pokemon, u16 species, u8 level, u8 fixedIv, u8 gender, u8 nature, u8 letter) +{ + u32 pid = 0; + u16 test = 0; + if (letter != 0 && letter < 29) + { + do { + pid = (u32)(rand_LC() | (rand_LC() << 16)); + test = (u16)CALC_UNOWN_LETTER(pid); + } while (nature != GetNatureFromPersonality(pid) || gender != GetGenderBySpeciesAndPersonality(species, pid) || test != letter - 1); + } + else + { + pid = GenPersonalityByGenderAndNature(species, gender, nature); + } + CreateMon(pokemon, (int)species, (int)level, (int)fixedIv, 1, (int)pid, 0, 0); +} + +u32 GenPersonalityByGenderAndNature(u16 species, u8 gender, u8 nature) +{ + int pid = nature; + u8 ratio = (u8)GetMonBaseStat(species, BASE_GENDER_RATIO); + switch (ratio) + { + case MON_RATIO_MALE: + case MON_RATIO_FEMALE: + case MON_RATIO_UNKNOWN: + break; + default: + if (gender == MON_MALE) + { + // Smallest increment that forces the low byte to exceed the + // gender ratio, thus making the mon male + pid = 25 * ((ratio / 25) + 1); + pid += nature; + } + break; + } + return (u32)pid; +} |