|
|
@ -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<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,
|
|
|
|
//id: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
enum MapObjectError {
|
|
|
|
UnknownObjectType(u16, RawMapObject),
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl MapObject {
|
|
|
|
fn from_raw(raw: RawMapObject, episode: Episode) -> 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,
|
|
|
|
_ => 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<Option<MapObject>> {
|
|
|
|
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<Option<MapEnemy>> {
|
|
|
|
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<Option<MapE |
|
|
|
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz1)));
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
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<Option<MapE |
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Maps {
|
|
|
|
map_variants: [MapVariant; 15],
|
|
|
|
enemy_data: Vec<Option<MapEnemy>>
|
|
|
|
enemy_data: Vec<Option<MapEnemy>>,
|
|
|
|
object_data: Vec<Option<MapObject>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
|
|
|