fixed nature parsing

master
hheik 2023-04-01 17:21:18 +03:00
parent 642cd9a76a
commit 2917ba457e
2 changed files with 81 additions and 15 deletions

View File

@ -5,6 +5,7 @@ const PLAYER_PARTY_OFFSET: usize = 0x21E42C;
const ENEMY_PARTY_OFFSET: usize = 0x258874; const ENEMY_PARTY_OFFSET: usize = 0x258874;
const POKEMON_SIZE: usize = 0xDC; const POKEMON_SIZE: usize = 0xDC;
const PARTY_MAX_SIZE: usize = 6; 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 /// All the block offsets for table A (growth) based on pokemon's shift value
const OFFSET_TABLE_A: [usize; 24] = [ const OFFSET_TABLE_A: [usize; 24] = [
@ -47,13 +48,15 @@ fn try_parse(data: &[u8], offset: usize) -> Option<PokemonInstance> {
return None; return None;
} }
let decrypted = decrypt_pokemon(encrypted).ok()?; let decrypted = decrypt_pokemon(encrypted).ok()?;
// println!("pokemon:\n{decrypted:?}");
let pokemon = parse_pokemon(&decrypted).ok()?; let pokemon = parse_pokemon(&decrypted).ok()?;
Some(pokemon) Some(pokemon)
} }
/// Decrypts and unshuffles pokemon data
fn decrypt_pokemon(encrypted: &[u8]) -> Result<Vec<u8>, String> { fn decrypt_pokemon(encrypted: &[u8]) -> Result<Vec<u8>, String> {
validate_size(encrypted)?; validate_size(encrypted)?;
// Decrypt data
const PRNG_ADD: u32 = 0x6073; const PRNG_ADD: u32 = 0x6073;
const PRNG_MULT: u32 = 0x41C64E6D; const PRNG_MULT: u32 = 0x41C64E6D;
@ -74,7 +77,6 @@ fn decrypt_pokemon(encrypted: &[u8]) -> Result<Vec<u8>, String> {
} }
let mut prng = header.pid as u32; let mut prng = header.pid as u32;
// for i in (0x88..0xEC).step_by(2) {
for i in (0x88..0xDC).step_by(2) { for i in (0x88..0xDC).step_by(2) {
prng = prng.wrapping_mul(PRNG_MULT).wrapping_add(PRNG_ADD); prng = prng.wrapping_mul(PRNG_MULT).wrapping_add(PRNG_ADD);
let decrypted_bytes = (read_short(encrypted, i) ^ (prng >> 16) as u16).to_le_bytes(); let decrypted_bytes = (read_short(encrypted, i) ^ (prng >> 16) as u16).to_le_bytes();
@ -82,28 +84,43 @@ fn decrypt_pokemon(encrypted: &[u8]) -> Result<Vec<u8>, String> {
decrypted[i + 1] = decrypted_bytes[1]; decrypted[i + 1] = decrypted_bytes[1];
} }
Ok(decrypted) // Reverse block shuffling
}
fn parse_pokemon(data: &[u8]) -> Result<PokemonInstance, String> {
validate_size(data)?;
const SHUFFLE_AND: u32 = 0x3E000; const SHUFFLE_AND: u32 = 0x3E000;
const SHUFFLE_RSHIFT: u32 = 0xD; 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 shift = ((header.pid & SHUFFLE_AND) >> SHUFFLE_RSHIFT) % 24;
let offset_a: usize = OFFSET_TABLE_A[shift as usize] * BLOCK_SIZE + 0x08; 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_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_c: usize = OFFSET_TABLE_C[shift as usize] * BLOCK_SIZE + 0x08;
let offset_d: usize = OFFSET_TABLE_D[shift as usize] * BLOCK_SIZE + 0x08; let offset_d: usize = OFFSET_TABLE_D[shift as usize] * BLOCK_SIZE + 0x08;
instance.nature = Some(Nature { let mut unshuffled = decrypted.clone();
pid: (header.pid % 25) as u8,
..Default::default() 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<PokemonInstance, String> {
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); instance.pokemon.national = read_short(data, offset_a + 0x00);
@ -129,6 +146,11 @@ fn parse_pokemon(data: &[u8]) -> Result<PokemonInstance, String> {
((ivs >> 25) & 31) as u8, ((ivs >> 25) & 31) as u8,
); );
instance.nature = Some(Nature {
pid: read_byte(data, offset_b + 0x19),
..Default::default()
});
Ok(instance) Ok(instance)
} }
@ -177,3 +199,45 @@ fn read_long(data: &[u8], offset: usize) -> u32 {
| ((data[offset + 2] as u32) << 16) | ((data[offset + 2] as u32) << 16)
| ((data[offset + 3] as u32) << 24) | ((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
}

View File

@ -68,6 +68,8 @@ fn flush_updates(
.find(|nature| nature.pid == instance_nature.pid) .find(|nature| nature.pid == instance_nature.pid)
{ {
instance.nature = Some(nature.clone()); instance.nature = Some(nature.clone());
} else {
warn!("Nature pid not found: {}", instance_nature.pid);
} }
} }
} }