From 2917ba457e5e752a45310e7ad2ac7b8a52b3f0f8 Mon Sep 17 00:00:00 2001 From: hheik <4469778+hheik@users.noreply.github.com> Date: Sat, 1 Apr 2023 17:21:18 +0300 Subject: [PATCH] fixed nature parsing --- src/ivpeek/battle.rs | 94 +++++++++++++++++++++++++++++++------ src/ivpeek/memory_reader.rs | 2 + 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/src/ivpeek/battle.rs b/src/ivpeek/battle.rs index beffe48..f8110a5 100644 --- a/src/ivpeek/battle.rs +++ b/src/ivpeek/battle.rs @@ -5,6 +5,7 @@ const PLAYER_PARTY_OFFSET: usize = 0x21E42C; const ENEMY_PARTY_OFFSET: usize = 0x258874; const POKEMON_SIZE: usize = 0xDC; const PARTY_MAX_SIZE: usize = 6; +const BLOCK_SIZE: usize = 0x20; /// All the block offsets for table A (growth) based on pokemon's shift value const OFFSET_TABLE_A: [usize; 24] = [ @@ -47,13 +48,15 @@ fn try_parse(data: &[u8], offset: usize) -> Option { return None; } let decrypted = decrypt_pokemon(encrypted).ok()?; - // println!("pokemon:\n{decrypted:?}"); let pokemon = parse_pokemon(&decrypted).ok()?; Some(pokemon) } +/// Decrypts and unshuffles pokemon data fn decrypt_pokemon(encrypted: &[u8]) -> Result, String> { validate_size(encrypted)?; + + // Decrypt data const PRNG_ADD: u32 = 0x6073; const PRNG_MULT: u32 = 0x41C64E6D; @@ -74,7 +77,6 @@ fn decrypt_pokemon(encrypted: &[u8]) -> Result, String> { } let mut prng = header.pid as u32; - // for i in (0x88..0xEC).step_by(2) { for i in (0x88..0xDC).step_by(2) { prng = prng.wrapping_mul(PRNG_MULT).wrapping_add(PRNG_ADD); let decrypted_bytes = (read_short(encrypted, i) ^ (prng >> 16) as u16).to_le_bytes(); @@ -82,28 +84,43 @@ fn decrypt_pokemon(encrypted: &[u8]) -> Result, String> { decrypted[i + 1] = decrypted_bytes[1]; } - Ok(decrypted) -} - -fn parse_pokemon(data: &[u8]) -> Result { - validate_size(data)?; + // Reverse block shuffling const SHUFFLE_AND: u32 = 0x3E000; const SHUFFLE_RSHIFT: u32 = 0xD; - const BLOCK_SIZE: usize = 0x20; - let mut instance = PokemonInstance::default(); - - let header = read_header(data)?; let shift = ((header.pid & SHUFFLE_AND) >> SHUFFLE_RSHIFT) % 24; let offset_a: usize = OFFSET_TABLE_A[shift as usize] * BLOCK_SIZE + 0x08; let offset_b: usize = OFFSET_TABLE_B[shift as usize] * BLOCK_SIZE + 0x08; let offset_c: usize = OFFSET_TABLE_C[shift as usize] * BLOCK_SIZE + 0x08; let offset_d: usize = OFFSET_TABLE_D[shift as usize] * BLOCK_SIZE + 0x08; - instance.nature = Some(Nature { - pid: (header.pid % 25) as u8, - ..Default::default() - }); + let mut unshuffled = decrypted.clone(); + + for i in 0..BLOCK_SIZE { + unshuffled[0x08 + 0 * BLOCK_SIZE + i] = decrypted[offset_a + i]; + } + for i in 0..BLOCK_SIZE { + unshuffled[0x08 + 1 * BLOCK_SIZE + i] = decrypted[offset_b + i]; + } + for i in 0..BLOCK_SIZE { + unshuffled[0x08 + 2 * BLOCK_SIZE + i] = decrypted[offset_c + i]; + } + for i in 0..BLOCK_SIZE { + unshuffled[0x08 + 3 * BLOCK_SIZE + i] = decrypted[offset_d + i]; + } + + Ok(unshuffled) +} + +fn parse_pokemon(data: &[u8]) -> Result { + validate_size(data)?; + + let mut instance = PokemonInstance::default(); + + let offset_a: usize = 0x08 + 0 * BLOCK_SIZE; + let offset_b: usize = 0x08 + 1 * BLOCK_SIZE; + let offset_c: usize = 0x08 + 2 * BLOCK_SIZE; + let offset_d: usize = 0x08 + 3 * BLOCK_SIZE; instance.pokemon.national = read_short(data, offset_a + 0x00); @@ -129,6 +146,11 @@ fn parse_pokemon(data: &[u8]) -> Result { ((ivs >> 25) & 31) as u8, ); + instance.nature = Some(Nature { + pid: read_byte(data, offset_b + 0x19), + ..Default::default() + }); + Ok(instance) } @@ -177,3 +199,45 @@ fn read_long(data: &[u8], offset: usize) -> u32 { | ((data[offset + 2] as u32) << 16) | ((data[offset + 3] as u32) << 24) } + +fn debug_pokemon_data(data: &[u8]) -> String { + let mut result = String::new(); + let mut offset = 0; + for (address, value) in data.iter().enumerate() { + offset = match address { + 0x00 => { + result += "---------header-------------\n"; + 0x00 + } + 0x08 => { + result += "---------block A (growth)---\n"; + 0x08 + } + 0x28 => { + result += "---------block B (effort)---\n"; + 0x28 + } + 0x48 => { + result += "---------block C (battle)---\n"; + 0x48 + } + 0x68 => { + result += "---------block D (misc)-----\n"; + 0x68 + } + 0x88 => { + result += "---------battle-------------\n"; + 0x88 + } + _ => offset, + }; + if address % 4 == 0 { + result += format!("[ {:#06X} ]", address - offset).as_str(); + } + result += format!(" {value:#04X}").as_str(); + if address % 4 == 3 { + result += "\n"; + } + } + result +} diff --git a/src/ivpeek/memory_reader.rs b/src/ivpeek/memory_reader.rs index f435012..d0fa11b 100644 --- a/src/ivpeek/memory_reader.rs +++ b/src/ivpeek/memory_reader.rs @@ -68,6 +68,8 @@ fn flush_updates( .find(|nature| nature.pid == instance_nature.pid) { instance.nature = Some(nature.clone()); + } else { + warn!("Nature pid not found: {}", instance_nature.pid); } } }