doukutsu-rs/src/map.rs

121 lines
3.2 KiB
Rust
Raw Normal View History

2020-08-18 16:46:07 +00:00
use std::io;
use byteorder::{LE, ReadBytesExt};
use ggez::GameError::ResourceLoadError;
use ggez::GameResult;
2020-08-28 04:55:45 +00:00
use crate::str;
2020-09-03 12:19:46 +00:00
static SUPPORTED_PXM_VERSIONS: [u8; 1] = [0x10];
static SUPPORTED_PXE_VERSIONS: [u8; 2] = [0, 0x10];
2020-08-18 16:46:07 +00:00
pub struct Map {
2021-01-01 01:46:01 +00:00
pub width: u16,
pub height: u16,
2020-08-18 16:46:07 +00:00
pub tiles: Vec<u8>,
pub attrib: [u8; 0x100],
}
impl Map {
2020-09-03 12:19:46 +00:00
pub fn load_from<R: io::Read>(mut map_data: R, mut attrib_data: R) -> GameResult<Map> {
2020-08-18 16:46:07 +00:00
let mut magic = [0; 3];
map_data.read_exact(&mut magic)?;
if &magic != b"PXM" {
2020-09-03 12:19:46 +00:00
return Err(ResourceLoadError(str!("Invalid magic")));
2020-08-18 16:46:07 +00:00
}
2020-09-03 12:19:46 +00:00
let version = map_data.read_u8()?;
// It's something Booster's Lab supports but I haven't seen anywhere being used in practice
if !SUPPORTED_PXM_VERSIONS.contains(&version) {
return Err(ResourceLoadError(format!("Unsupported PXM version: {:#x}", version)));
}
2020-08-18 16:46:07 +00:00
2021-01-01 01:46:01 +00:00
let width = map_data.read_u16::<LE>()?;
let height = map_data.read_u16::<LE>()?;
let mut tiles = vec![0u8; (width * height) as usize];
2020-08-18 16:46:07 +00:00
let mut attrib = [0u8; 0x100];
2020-09-11 16:30:18 +00:00
log::info!("Map size: {}x{}", width, height);
2020-08-18 16:46:07 +00:00
map_data.read_exact(&mut tiles)?;
2020-09-11 16:30:18 +00:00
if attrib_data.read_exact(&mut attrib).is_err() {
log::warn!("Map attribute data is shorter than 256 bytes!");
}
2020-08-18 16:46:07 +00:00
2020-09-03 12:19:46 +00:00
Ok(Map {
2020-08-18 16:46:07 +00:00
width,
height,
tiles,
attrib,
2020-09-03 12:19:46 +00:00
})
2020-08-18 16:46:07 +00:00
}
pub fn get_attribute(&self, x: usize, y: usize) -> u8 {
2021-01-01 01:46:01 +00:00
if x >= self.width as usize || y >= self.height as usize {
2020-10-01 03:06:18 +00:00
return 0;
}
2021-01-01 01:46:01 +00:00
self.attrib[*self.tiles.get(self.width as usize * y + x).unwrap_or_else(|| &0u8) as usize]
2020-08-18 16:46:07 +00:00
}
}
2020-09-03 12:19:46 +00:00
2020-09-04 23:08:33 +00:00
#[derive(Debug)]
2020-09-03 12:19:46 +00:00
pub struct NPCData {
2020-09-04 23:08:33 +00:00
pub id: u16,
2020-09-03 12:29:59 +00:00
pub x: i16,
pub y: i16,
2020-09-05 02:09:52 +00:00
pub flag_num: u16,
2020-09-03 12:29:59 +00:00
pub event_num: u16,
pub npc_type: u16,
pub flags: u16,
pub layer: u8,
2020-09-03 12:19:46 +00:00
}
impl NPCData {
2020-09-04 23:08:33 +00:00
pub fn load_from<R: io::Read>(mut data: R) -> GameResult<Vec<NPCData>> {
2020-09-03 12:19:46 +00:00
let mut magic = [0; 3];
2020-09-04 23:08:33 +00:00
data.read_exact(&mut magic)?;
2020-09-03 12:19:46 +00:00
if &magic != b"PXE" {
return Err(ResourceLoadError(str!("Invalid magic")));
}
2020-09-04 23:08:33 +00:00
let version = data.read_u8()?;
2020-09-03 12:19:46 +00:00
if !SUPPORTED_PXE_VERSIONS.contains(&version) {
return Err(ResourceLoadError(format!("Unsupported PXE version: {:#x}", version)));
}
2020-09-04 23:08:33 +00:00
let count = data.read_u32::<LE>()? as usize;
2020-09-03 12:19:46 +00:00
let mut npcs = Vec::with_capacity(count);
2020-09-04 23:08:33 +00:00
for i in 0..count {
let x = data.read_i16::<LE>()?;
let y = data.read_i16::<LE>()?;
2020-09-05 02:09:52 +00:00
let flag_num = data.read_u16::<LE>()?;
2020-09-04 23:08:33 +00:00
let event_num = data.read_u16::<LE>()?;
let npc_type = data.read_u16::<LE>()?;
let flags = data.read_u16::<LE>()?;
2020-09-03 12:19:46 +00:00
// booster's lab also specifies a layer field in version 0x10, prob for multi-layered maps
2020-09-04 23:08:33 +00:00
let layer = if version == 0x10 { data.read_u8()? } else { 0 };
2020-09-03 12:19:46 +00:00
npcs.push(NPCData {
2020-09-04 23:08:33 +00:00
id: 170 + i as u16,
2020-09-03 12:19:46 +00:00
x,
y,
2020-09-05 02:09:52 +00:00
flag_num,
2020-09-03 12:19:46 +00:00
event_num,
npc_type,
flags,
layer,
})
}
Ok(npcs)
}
}