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.

331 lines
14 KiB

// 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<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,
// 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<MapObject, MapObjectError> {
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,
})
}
}