You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
5.5 KiB

// TOOD: `pub(super) for most of these?`
use std::io::Read;
use byteorder::{LittleEndian, ReadBytesExt};
use crate::room::Episode;
use crate::area::MapArea;
#[derive(Debug, Copy, Clone)]
pub struct RawMapObject {
otype: u16,
_unknown1: u16,
_unknown2: u32,
_id: u16,
_group: u16,
_section: u16,
_unknown3: u16,
_x: f32,
_y: f32,
_z: f32,
_xrot: u32,
_yrot: u32,
_zrot: u32,
field1: f32,
field2: f32,
field3: f32,
field4: u32,
_field5: u32,
_field6: u32,
_field7: u32,
}
impl RawMapObject {
pub fn from_byte_stream<R: Read>(cursor: &mut R) -> Result<RawMapObject, std::io::Error> {
Ok(RawMapObject {
otype: cursor.read_u16::<LittleEndian>()?,
_unknown1: cursor.read_u16::<LittleEndian>()?,
_unknown2: cursor.read_u32::<LittleEndian>()?,
_id: cursor.read_u16::<LittleEndian>()?,
_group: cursor.read_u16::<LittleEndian>()?,
_section: cursor.read_u16::<LittleEndian>()?,
_unknown3: cursor.read_u16::<LittleEndian>()?,
_x: cursor.read_f32::<LittleEndian>()?,
_y: cursor.read_f32::<LittleEndian>()?,
_z: cursor.read_f32::<LittleEndian>()?,
_xrot: cursor.read_u32::<LittleEndian>()?,
_yrot: cursor.read_u32::<LittleEndian>()?,
_zrot: cursor.read_u32::<LittleEndian>()?,
field1: cursor.read_f32::<LittleEndian>()?,
field2: cursor.read_f32::<LittleEndian>()?,
field3: cursor.read_f32::<LittleEndian>()?,
field4: cursor.read_u32::<LittleEndian>()?,
_field5: cursor.read_u32::<LittleEndian>()?,
_field6: cursor.read_u32::<LittleEndian>()?,
_field7: cursor.read_u32::<LittleEndian>()?,
})
}
}
#[derive(Debug, Copy, Clone)]
pub enum FixedBoxDropType {
Weapon,
Armor,
Tool,
Meseta,
Random,
Specific(u32), // TODO: ItemDropType
}
impl FixedBoxDropType {
fn from_object(field1: f32, field2: f32, field3: f32, field4: u32) -> FixedBoxDropType {
match (field1.round() as i32, field2.round() as i32, field3.round() as i32, field4) {
(0, 1, 1, 0) => {
FixedBoxDropType::Random
},
(0, 1, _, 0x4000000) => {
FixedBoxDropType::Meseta
},
(0, 1, 1, _) => {
FixedBoxDropType::Specific(field4)
},
(-1, 1, 1, _) => { // ???????
FixedBoxDropType::Specific(field4)
},
(0, 1, 0, 0) => {
FixedBoxDropType::Weapon
},
(0, 1, 0, 0x1000000) => {
FixedBoxDropType::Armor
},
(0, 1, 0, 0x3000000) => {
FixedBoxDropType::Tool
},
(1, _, _, _) => {
FixedBoxDropType::Random
},
_ => {
println!("this box state should not occur? {} {} {} {}", field1.round() as i32, field2.round() as i32, field3.round() as i32, field4);
FixedBoxDropType::Random
}
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum MapObjectType {
Box,
FixedBox(FixedBoxDropType),
EnemyBox,
EnemyFixedBox(FixedBoxDropType),
RuinsBox,
RuinsFixedBox(FixedBoxDropType),
RuinsEnemyBox,
RuinsEnemyFixedBox(FixedBoxDropType),
CcaBox,
CcaFixedBox(FixedBoxDropType),
EmptyBox,
EmptyFixedBox(FixedBoxDropType),
RuinsEmptyBox,
RuinsEmptyFixedBox,
}
#[derive(Debug, Copy, Clone)]
pub struct MapObject {
pub object: MapObjectType,
pub map: MapArea,
pub dropped_item: bool,
//id: u32,
}
#[derive(Debug, Copy, Clone)]
pub enum MapObjectError {
UnknownObjectType(u16, RawMapObject),
}
impl MapObject {
pub fn from_raw(raw: RawMapObject, episode: Episode, map_area: &MapArea) -> Result<MapObject, MapObjectError> {
let object = match (raw, episode) {
(RawMapObject {otype: 136, ..}, _) => MapObjectType::Box,
(RawMapObject {otype: 145, ..}, _) => MapObjectType::EnemyBox,
(RawMapObject {otype: 146, ..}, _) => MapObjectType::FixedBox(FixedBoxDropType::from_object(raw.field1, raw.field2, raw.field3, raw.field4)),
(RawMapObject {otype: 147, ..}, _) => MapObjectType::EnemyFixedBox(FixedBoxDropType::from_object(raw.field1, raw.field2, raw.field3, raw.field4)),
(RawMapObject {otype: 149, ..}, _) => MapObjectType::EmptyFixedBox(FixedBoxDropType::from_object(raw.field1, raw.field2, raw.field3, raw.field4)),
(RawMapObject {otype: 353, ..}, _) => MapObjectType::RuinsFixedBox(FixedBoxDropType::from_object(raw.field1, raw.field2, raw.field3, raw.field4)),
(RawMapObject {otype: 354, ..}, _) => MapObjectType::RuinsBox,
(RawMapObject {otype: 355, ..}, _) => MapObjectType::RuinsEnemyFixedBox(FixedBoxDropType::from_object(raw.field1, raw.field2, raw.field3, raw.field4)),
(RawMapObject {otype: 356, ..}, _) => MapObjectType::RuinsEnemyBox,
(RawMapObject {otype: 357, ..}, _) => MapObjectType::RuinsEmptyBox,
(RawMapObject {otype: 512, ..}, _) => MapObjectType::CcaBox,
(RawMapObject {otype: 515, ..}, _) => MapObjectType::CcaFixedBox(FixedBoxDropType::from_object(raw.field1, raw.field2, raw.field3, raw.field4)),
_ => return Err(MapObjectError::UnknownObjectType(raw.otype, raw))
};
Ok(MapObject {
object,
map: *map_area,
dropped_item: false,
})
}
}