diff --git a/src/ship/map.rs b/src/ship/map.rs index 8da7789..c8c4866 100644 --- a/src/ship/map.rs +++ b/src/ship/map.rs @@ -183,6 +183,156 @@ impl MapEnemy { } } +#[derive(Debug, Copy, Clone)] +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 { + fn from_byte_stream(cursor: &mut R) -> Result { + Ok(RawMapObject { + otype: cursor.read_u16::()?, + unknown1: cursor.read_u16::()?, + unknown2: cursor.read_u32::()?, + id: cursor.read_u16::()?, + group: cursor.read_u16::()?, + section: cursor.read_u16::()?, + unknown3: cursor.read_u16::()?, + x: cursor.read_f32::()?, + y: cursor.read_f32::()?, + z: cursor.read_f32::()?, + xrot: cursor.read_u32::()?, + yrot: cursor.read_u32::()?, + zrot: cursor.read_u32::()?, + field1: cursor.read_f32::()?, + field2: cursor.read_f32::()?, + field3: cursor.read_f32::()?, + field4: cursor.read_u32::()?, + field5: cursor.read_u32::()?, + field6: cursor.read_u32::()?, + field7: cursor.read_u32::()?, + }) + } +} + + +#[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, + //id: u32, +} + +#[derive(Debug, Copy, Clone)] +enum MapObjectError { + UnknownObjectType(u16, RawMapObject), +} + + +impl MapObject { + fn from_raw(raw: RawMapObject, episode: Episode) -> Result { + 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, + _ => return Err(MapObjectError::UnknownObjectType(raw.otype, raw)) + }; + + Ok(MapObject { + object: object, + }) + } +} + #[derive(Debug)] enum MapVariantMode { @@ -269,7 +419,7 @@ impl MapVariant { minor: minor, } } - + // TODO: rename to npc_file fn dat_file(&self) -> String { match self.map { MapVariantType::Pioneer2Ep1 => "data/maps/map_city00_00e.dat".into(), @@ -290,12 +440,45 @@ impl MapVariant { } } + fn obj_file(&self) -> String { + match self.map { + MapVariantType::Pioneer2Ep1 => "data/maps/map_city00_00e.dat".into(), + MapVariantType::Forest1 => format!("data/maps/map_forest01_0{}o.dat", self.minor), + MapVariantType::Forest2 => format!("data/maps/map_forest02_0{}o.dat", self.minor), + MapVariantType::Caves1 => format!("data/maps/map_cave01_0{}_0{}o.dat", self.major, self.minor), + MapVariantType::Caves2 => format!("data/maps/map_cave02_0{}_0{}o.dat", self.major, self.minor), + MapVariantType::Caves3 => format!("data/maps/map_cave03_0{}_0{}o.dat", self.major, self.minor), + MapVariantType::Mines1 => format!("data/maps/map_machine01_0{}_0{}o.dat", self.major, self.minor), + MapVariantType::Mines2 => format!("data/maps/map_machine02_0{}_0{}o.dat", self.major, self.minor), + MapVariantType::Ruins1 => format!("data/maps/map_ancient01_0{}_0{}o.dat", self.major, self.minor), + MapVariantType::Ruins2 => format!("data/maps/map_ancient02_0{}_0{}o.dat", self.major, self.minor), + MapVariantType::Ruins3 => format!("data/maps/map_ancient03_0{}_0{}o.dat", self.major, self.minor), + MapVariantType::Dragon => "data/maps/map_boss01o.dat".into(), + MapVariantType::DeRolLe => "data/maps/map_boss02o.dat".into(), + MapVariantType::VolOpt => "data/maps/map_boss03o.dat".into(), + MapVariantType::DarkFalz => "data/maps/map_boss04o.dat".into(), + } + } + fn pkt_header(&self) -> [u8; 2] { [self.major, self.minor] } } +fn objects_from_map_data(path: PathBuf, episode: &Episode) -> Vec> { + let mut cursor = File::open(path.clone()).unwrap(); + let mut object_data = Vec::new(); + + while let Ok(raw_object) = RawMapObject::from_byte_stream(&mut cursor) { + let object = MapObject::from_raw(raw_object.clone(), *episode); + object_data.push(object.ok()); + + } + object_data +} + + fn enemy_data_from_map_data(path: PathBuf, episode: &Episode) -> Vec> { let mut cursor = File::open(path).unwrap(); let mut enemy_data = Vec::new(); @@ -377,7 +560,6 @@ fn enemy_data_from_map_data(path: PathBuf, episode: &Episode) -> Vec { - warn!("children: {}", enemy.children); for _ in 0..enemy.children { monsters.push(Some(MapEnemy::new(monster.monster))); } @@ -393,12 +575,12 @@ fn enemy_data_from_map_data(path: PathBuf, episode: &Episode) -> Vec> + enemy_data: Vec>, + object_data: Vec>, } impl Maps { pub fn new(episode: Episode) -> Maps { - warn!("new maps ep: {:?}", episode); let map_variants = match episode { Episode::One => { [MapVariant::new(MapVariantType::Pioneer2Ep1, MapVariantMode::Online), @@ -426,6 +608,9 @@ impl Maps { enemy_data.append(&mut enemy_data_from_map_data(map_variant.dat_file().into(), &episode)); enemy_data }), + object_data: map_variants.iter().map(|map_variant| { + objects_from_map_data(map_variant.obj_file().into(), &episode) + }).flatten().collect(), map_variants: map_variants, };