use std::io; use byteorder::{LE, ReadBytesExt}; use crate::framework::context::Context; use crate::framework::error::GameResult; use crate::str; use crate::framework::error::GameError::ResourceLoadError; static SUPPORTED_PXM_VERSIONS: [u8; 1] = [0x10]; static SUPPORTED_PXE_VERSIONS: [u8; 2] = [0, 0x10]; pub struct Map { pub width: u16, pub height: u16, pub tiles: Vec, pub attrib: [u8; 0x100], } impl Map { pub fn load_from(mut map_data: R, mut attrib_data: R) -> GameResult { let mut magic = [0; 3]; map_data.read_exact(&mut magic)?; if &magic != b"PXM" { return Err(ResourceLoadError(str!("Invalid magic"))); } let version = map_data.read_u8()?; if !SUPPORTED_PXM_VERSIONS.contains(&version) { return Err(ResourceLoadError(format!("Unsupported PXM version: {:#x}", version))); } let width = map_data.read_u16::()?; let height = map_data.read_u16::()?; let mut tiles = vec![0u8; (width * height) as usize]; let mut attrib = [0u8; 0x100]; log::info!("Map size: {}x{}", width, height); map_data.read_exact(&mut tiles)?; if attrib_data.read_exact(&mut attrib).is_err() { log::warn!("Map attribute data is shorter than 256 bytes!"); } Ok(Map { width, height, tiles, attrib, }) } pub fn get_attribute(&self, x: usize, y: usize) -> u8 { if x >= self.width as usize || y >= self.height as usize { return 0; } self.attrib[*self.tiles.get(self.width as usize * y + x).unwrap_or_else(|| &0u8) as usize] } } #[derive(Debug)] pub struct NPCData { pub id: u16, pub x: i16, pub y: i16, pub flag_num: u16, pub event_num: u16, pub npc_type: u16, pub flags: u16, pub layer: u8, } impl NPCData { pub fn load_from(mut data: R) -> GameResult> { let mut magic = [0; 3]; data.read_exact(&mut magic)?; if &magic != b"PXE" { return Err(ResourceLoadError(str!("Invalid magic"))); } let version = data.read_u8()?; if !SUPPORTED_PXE_VERSIONS.contains(&version) { return Err(ResourceLoadError(format!("Unsupported PXE version: {:#x}", version))); } let count = data.read_u32::()? as usize; let mut npcs = Vec::with_capacity(count); for i in 0..count { let x = data.read_i16::()?; let y = data.read_i16::()?; let flag_num = data.read_u16::()?; let event_num = data.read_u16::()?; let npc_type = data.read_u16::()?; let flags = data.read_u16::()?; // booster's lab also specifies a layer field in version 0x10, prob for multi-layered maps let layer = if version == 0x10 { data.read_u8()? } else { 0 }; npcs.push(NPCData { id: 170 + i as u16, x, y, flag_num, event_num, npc_type, flags, layer, }) } Ok(npcs) } }