// TOOD: `pub(super) for most of these?` use std::io::{Read}; use byteorder::{LittleEndian, ReadBytesExt}; use crate::ship::room::Episode; // TODO: don't use * use crate::ship::map::*; #[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(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, // taken from qedit v1.0 public // TODO: update names // TODO: add missing objects // TODO: sort by otype MenuActivation, PlaceHolder, SpawnPosition, Teleporter, PrincipalWarp, TelepipeLocation, MedicalCenterDoor, ShopDoor, HuntersGuildDoor, TeleporterDoor, RicoMessagePod, BossTeleporter, MapDetect, SetEventActivation, ForestDoor, RandomTypeBox1, // is this different than "Box"? ForestConsole, CavesNormalDoor, FloorPanel2, // implies floor panel 1? TouchPlateObject, EffectObject, CavesSmashingPillar, LaserFenceEx, // Ex?? MinesDoor, PopupTrapsTechs, Ruins3Door, RuinsWarpSiteToSite, RuinsTeleporter, RuinsPillarTrap, // falling cage trap Darkness, RandomBoxTypeRuins, // is this different than "Box"? FunctionTouchPlate, Warp, // found in vol opt map? RuinsSeal, // totem door. unused in bb? Poison, // found in vol opt map? poison fog?? LobbyTeleporter, MainRagolTeleporter, Pioneer2InvisibleTouchplate, LaserFence, ForestLaserFenceSwitch, ElementalTrap, StatusTrap, HealTrap, HealRing, ForestSwitch, LaserSquareFence, Probe, ForestWeatherStation, LaserBarrierDoor, ForestRisingBridge, SwitchNoneDoor, FloorPanel1, Caves4ButtonDoor, CavesSign1, CavesSign3, CavesSwitchDoor, Caves1LargeRedRock, Caves2SmallRock1, Caves2LargeRock2, FloorPanel3, MinesSwitchDoor, MinesLargeFlashingCrate, RuinsSwitch, FloorPanel4, Ruins1Door, Ruins2Door, Ruins4ButtonDoor, Ruins2ButtonDoor, RuinsFenceSwitch, RuinsLaserFence4x2, RuinsLaserFence6x2, RuinsPoisonBlob, RuinsCrystal, Monument, RuinsRock1, RuinsRock2, RuinsRock3, RuinsRock4, RuinsRock5, RuinsRock6, } #[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 { let object = match (raw, episode) { (RawMapObject {otype: 0, ..}, _) => MapObjectType::SpawnPosition, (RawMapObject {otype: 2, ..}, _) => MapObjectType::Teleporter, (RawMapObject {otype: 3, ..}, _) => MapObjectType::Warp, (RawMapObject {otype: 8, ..}, _) => MapObjectType::SetEventActivation, (RawMapObject {otype: 10, ..}, _) => MapObjectType::ElementalTrap, (RawMapObject {otype: 11, ..}, _) => MapObjectType::StatusTrap, (RawMapObject {otype: 12, ..}, _) => MapObjectType::HealTrap, (RawMapObject {otype: 14, ..}, _) => MapObjectType::MapDetect, (RawMapObject {otype: 18, ..}, _) => MapObjectType::FunctionTouchPlate, (RawMapObject {otype: 19, ..}, _) => MapObjectType::HealRing, (RawMapObject {otype: 24, ..}, _) => MapObjectType::Darkness, (RawMapObject {otype: 25, ..}, _) => MapObjectType::BossTeleporter, (RawMapObject {otype: 34, ..}, _) => MapObjectType::TouchPlateObject, (RawMapObject {otype: 36, ..}, _) => MapObjectType::EffectObject, (RawMapObject {otype: 64, ..}, _) => MapObjectType::MenuActivation, (RawMapObject {otype: 65, ..}, _) => MapObjectType::TelepipeLocation, (RawMapObject {otype: 67, ..}, _) => MapObjectType::MainRagolTeleporter, (RawMapObject {otype: 68, ..}, _) => MapObjectType::LobbyTeleporter, (RawMapObject {otype: 69, ..}, _) => MapObjectType::PrincipalWarp, (RawMapObject {otype: 70, ..}, _) => MapObjectType::ShopDoor, (RawMapObject {otype: 71, ..}, _) => MapObjectType::HuntersGuildDoor, (RawMapObject {otype: 72, ..}, _) => MapObjectType::TeleporterDoor, (RawMapObject {otype: 73, ..}, _) => MapObjectType::MedicalCenterDoor, (RawMapObject {otype: 87, ..}, _) => MapObjectType::Pioneer2InvisibleTouchplate, (RawMapObject {otype: 128, ..}, _) => MapObjectType::ForestDoor, (RawMapObject {otype: 129, ..}, _) => MapObjectType::ForestSwitch, (RawMapObject {otype: 130, ..}, _) => MapObjectType::LaserFence, (RawMapObject {otype: 131, ..}, _) => MapObjectType::LaserSquareFence, (RawMapObject {otype: 132, ..}, _) => MapObjectType::ForestLaserFenceSwitch, (RawMapObject {otype: 135, ..}, _) => MapObjectType::Probe, (RawMapObject {otype: 137, ..}, _) => MapObjectType::ForestWeatherStation, (RawMapObject {otype: 139, ..}, _) => MapObjectType::ForestConsole, (RawMapObject {otype: 141, ..}, _) => MapObjectType::RicoMessagePod, (RawMapObject {otype: 142, ..}, _) => MapObjectType::LaserBarrierDoor, (RawMapObject {otype: 143, ..}, _) => MapObjectType::ForestRisingBridge, (RawMapObject {otype: 144, ..}, _) => MapObjectType::SwitchNoneDoor, (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: 150, ..}, _) => MapObjectType::LaserFenceEx, (RawMapObject {otype: 192, ..}, _) => MapObjectType::FloorPanel1, (RawMapObject {otype: 193, ..}, _) => MapObjectType::Caves4ButtonDoor, (RawMapObject {otype: 194, ..}, _) => MapObjectType::CavesNormalDoor, (RawMapObject {otype: 195, ..}, _) => MapObjectType::CavesSmashingPillar, (RawMapObject {otype: 196, ..}, _) => MapObjectType::CavesSign1, (RawMapObject {otype: 198, ..}, _) => MapObjectType::CavesSign3, (RawMapObject {otype: 206, ..}, _) => MapObjectType::CavesSwitchDoor, (RawMapObject {otype: 211, ..}, _) => MapObjectType::Caves1LargeRedRock, (RawMapObject {otype: 212, ..}, _) => MapObjectType::Caves2SmallRock1, (RawMapObject {otype: 217, ..}, _) => MapObjectType::Caves2LargeRock2, (RawMapObject {otype: 222, ..}, _) => MapObjectType::FloorPanel2, (RawMapObject {otype: 256, ..}, _) => MapObjectType::MinesDoor, (RawMapObject {otype: 257, ..}, _) => MapObjectType::FloorPanel3, (RawMapObject {otype: 258, ..}, _) => MapObjectType::MinesSwitchDoor, (RawMapObject {otype: 268, ..}, _) => MapObjectType::MinesLargeFlashingCrate, (RawMapObject {otype: 304, ..}, _) => MapObjectType::RuinsSeal, (RawMapObject {otype: 320, ..}, _) => MapObjectType::RuinsTeleporter, (RawMapObject {otype: 321, ..}, _) => MapObjectType::RuinsWarpSiteToSite, (RawMapObject {otype: 322, ..}, _) => MapObjectType::RuinsSwitch, (RawMapObject {otype: 323, ..}, _) => MapObjectType::FloorPanel4, (RawMapObject {otype: 324, ..}, _) => MapObjectType::Ruins1Door, (RawMapObject {otype: 325, ..}, _) => MapObjectType::Ruins3Door, (RawMapObject {otype: 326, ..}, _) => MapObjectType::Ruins2Door, (RawMapObject {otype: 330, ..}, _) => MapObjectType::Ruins4ButtonDoor, (RawMapObject {otype: 331, ..}, _) => MapObjectType::Ruins2ButtonDoor, (RawMapObject {otype: 333, ..}, _) => MapObjectType::RuinsFenceSwitch, (RawMapObject {otype: 334, ..}, _) => MapObjectType::RuinsLaserFence4x2, (RawMapObject {otype: 335, ..}, _) => MapObjectType::RuinsLaserFence6x2, (RawMapObject {otype: 338, ..}, _) => MapObjectType::RuinsPoisonBlob, (RawMapObject {otype: 339, ..}, _) => MapObjectType::RuinsPillarTrap, (RawMapObject {otype: 341, ..}, _) => MapObjectType::RuinsCrystal, (RawMapObject {otype: 342, ..}, _) => MapObjectType::Monument, (RawMapObject {otype: 345, ..}, _) => MapObjectType::RuinsRock1, (RawMapObject {otype: 346, ..}, _) => MapObjectType::RuinsRock2, (RawMapObject {otype: 347, ..}, _) => MapObjectType::RuinsRock3, (RawMapObject {otype: 348, ..}, _) => MapObjectType::RuinsRock4, (RawMapObject {otype: 349, ..}, _) => MapObjectType::RuinsRock5, (RawMapObject {otype: 350, ..}, _) => MapObjectType::RuinsRock6, (RawMapObject {otype: 352, ..}, _) => MapObjectType::Poison, (RawMapObject {otype: 359, ..}, _) => MapObjectType::PopupTrapsTechs, (RawMapObject {otype: 136, ..}, _) => MapObjectType::Box, (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 {println!("UNKNOWN OBJECT OTYPE --- ship::map::object::from_raw() - otype: {:?}, x: {:?}, y: {:?}, z: {:?}, id: {:?}, section: {:?}, maparea: {:?}, ", raw.otype, raw.x, raw.y, raw.z, raw.id, raw.section, map_area); Err(MapObjectError::UnknownObjectType(raw.otype, raw))} }; Ok(MapObject { object: object, map: map_area.clone(), dropped_item: false, }) } }