fixed nature parsing
parent
642cd9a76a
commit
2917ba457e
|
|
@ -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<PokemonInstance> {
|
|||
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<Vec<u8>, 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<Vec<u8>, 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<Vec<u8>, String> {
|
|||
decrypted[i + 1] = decrypted_bytes[1];
|
||||
}
|
||||
|
||||
Ok(decrypted)
|
||||
}
|
||||
|
||||
fn parse_pokemon(data: &[u8]) -> Result<PokemonInstance, String> {
|
||||
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<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);
|
||||
|
||||
|
|
@ -129,6 +146,11 @@ fn parse_pokemon(data: &[u8]) -> Result<PokemonInstance, String> {
|
|||
((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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue