fixed nature parsing
parent
642cd9a76a
commit
2917ba457e
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue