diff --git a/src/ivpeek/battle.rs b/src/ivpeek/battle.rs index 6d0688a..be6dffd 100644 --- a/src/ivpeek/battle.rs +++ b/src/ivpeek/battle.rs @@ -1,6 +1,81 @@ -use super::inspector::Battle; +use super::inspector::{Battle, PokemonInstance}; + +const PLAYER_PARTY_OFFSET: usize = 0x21E42C; +const ENEMY_PARTY_OFFSET: usize = 0x258874; +const POKEMON_SIZE: usize = 0xDC; +const PARTY_MAX_SIZE: usize = 6; pub fn parse_battle_party(data: &Vec) -> Result { - let mut result = Battle::default(); + let mut battle = Battle::default(); + for i in 0..PARTY_MAX_SIZE { + if let Some(instance) = try_parse(data, PLAYER_PARTY_OFFSET + i * POKEMON_SIZE) { + battle.player_party.push(instance); + } + if let Some(instance) = try_parse(data, ENEMY_PARTY_OFFSET + i * POKEMON_SIZE) { + battle.enemy_party.push(instance); + } + } + Ok(battle) +} + +fn try_parse(data: &[u8], offset: usize) -> Option { + let encrypted = &data[offset..offset + POKEMON_SIZE]; + if !contains_pokemon(encrypted) { + return None; + } + let decrypted = decrypt_pokemon(encrypted).ok()?; + let pokemon = parse_pokemon(&decrypted).ok()?; + Some(pokemon) +} + +fn decrypt_pokemon(encrypted: &[u8]) -> Result, String> { + validate_size(encrypted)?; + let mut result = vec![0; POKEMON_SIZE]; + // NOTIMP Ok(result) } + +fn parse_pokemon(decrypted: &[u8]) -> Result { + validate_size(decrypted)?; + let mut instance = PokemonInstance::default(); + // NOTIMP + Ok(instance) +} + +/// Check if the raw data contains a pokemon. +/// If the header section (8 bytes) are all 0x00, then the data doens't contain a pokemon. +/// This works with both encrypted and decryped forms, as the header is never encrypted. +fn contains_pokemon(data: &[u8]) -> bool { + if let Err(_) = validate_size(data) { + return false; + } + read_long(data, 0) != 0 || read_long(data, 4) != 0 +} + +fn validate_size(data: &[u8]) -> Result<(), String> { + if data.len() != POKEMON_SIZE { + return Err(format!( + "Invalid data size. expected: {POKEMON_SIZE} - actual: {}", + data.len() + )); + } + Ok(()) +} + +/// Read a 1 byte value +fn read_byte(data: &[u8], offset: usize) -> u8 { + data[offset] +} + +/// Read a little-endian 2 byte value +fn read_short(data: &[u8], offset: usize) -> u16 { + data[offset] as u16 | ((data[offset + 1] as u16) << 8) +} + +/// Read a little-endian 4 byte value +fn read_long(data: &[u8], offset: usize) -> u32 { + data[offset] as u32 + | ((data[offset + 1] as u32) << 8) + | ((data[offset + 2] as u32) << 16) + | ((data[offset + 3] as u32) << 24) +}