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
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,
|
|
})
|
|
}
|
|
}
|
|
|