elseware/src/ship/map.rs

638 lines
28 KiB
Rust
Raw Normal View History

2020-01-31 08:57:36 -08:00
use log::warn;
use std::io::Cursor;
use std::convert::Into;
use std::path::PathBuf;
use std::io::{Read};
use std::fs::File;
use byteorder::{LittleEndian, ReadBytesExt};
use rand::Rng;
2020-01-31 08:57:36 -08:00
use crate::ship::monster::MonsterType;
2020-02-20 22:56:49 -08:00
use crate::ship::room::Episode;
2020-01-31 08:57:36 -08:00
#[derive(Debug, Copy, Clone)]
struct RawMapEnemy {
id: u32,
_unknown1: u16,
children: u16,
_unknown3: u16,
_unknown4: u16,
section: u16,
wave_idd: u16,
wave_id: u32,
x: f32,
y: f32,
z: f32,
xrot: u32,
yrot: u32,
zrot: u32,
2020-02-20 22:54:23 -08:00
_field1: u32,
field2: u32,
_field3: u32,
_field4: u32,
_field5: u32,
2020-01-31 08:57:36 -08:00
skin: u32,
_field6: u32
}
impl RawMapEnemy {
fn from_byte_stream<R: Read>(cursor: &mut R) -> Result<RawMapEnemy, std::io::Error> {
Ok(RawMapEnemy {
id: cursor.read_u32::<LittleEndian>()?,
_unknown1: cursor.read_u16::<LittleEndian>()?,
children: cursor.read_u16::<LittleEndian>()?,
_unknown3: cursor.read_u16::<LittleEndian>()?,
_unknown4: cursor.read_u16::<LittleEndian>()?,
section: cursor.read_u16::<LittleEndian>()?,
wave_idd: cursor.read_u16::<LittleEndian>()?,
wave_id: cursor.read_u32::<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>()?,
2020-02-20 22:54:23 -08:00
_field1: cursor.read_u32::<LittleEndian>()?,
field2: cursor.read_u32::<LittleEndian>()?,
_field3: cursor.read_u32::<LittleEndian>()?,
_field4: cursor.read_u32::<LittleEndian>()?,
_field5: cursor.read_u32::<LittleEndian>()?,
2020-01-31 08:57:36 -08:00
skin: cursor.read_u32::<LittleEndian>()?,
_field6: cursor.read_u32::<LittleEndian>()?,
})
}
}
2020-02-20 22:56:49 -08:00
#[derive(Debug)]
enum MapEnemyError {
UnknownEnemyId(u32),
}
2020-01-31 08:57:36 -08:00
#[derive(Debug, Copy, Clone)]
pub struct MapEnemy {
pub monster: MonsterType,
hp: u32,
// other stats from bp.n
dead: bool,
}
impl MapEnemy {
2020-02-20 22:56:49 -08:00
fn from_raw(enemy: RawMapEnemy, episode: &Episode /*, battleparam */) -> Result<MapEnemy, MapEnemyError> {
let monster = match (enemy, episode) {
(RawMapEnemy {id: 64, ..}, _) => MonsterType::Hildebear,
(RawMapEnemy {id: 65, ..}, Episode::Four) => MonsterType::SandRappy,
(RawMapEnemy {id: 65, ..}, _) => MonsterType::RagRappy,
(RawMapEnemy {id: 66, ..}, _) => MonsterType::Monest,
(RawMapEnemy {id: 67, field2: 0, ..}, _) => MonsterType::SavageWolf,
(RawMapEnemy {id: 67, ..}, _) => MonsterType::BarbarousWolf,
(RawMapEnemy {id: 68, skin: 0, ..}, _) => MonsterType::Booma,
(RawMapEnemy {id: 68, skin: 1, ..}, _) => MonsterType::Gobooma,
(RawMapEnemy {id: 68, skin: 2, ..}, _) => MonsterType::Gigobooma,
(RawMapEnemy {id: 96, ..}, _) => MonsterType::GrassAssassin,
(RawMapEnemy {id: 97, ..}, Episode::Two) => MonsterType::DelLily,
(RawMapEnemy {id: 97, ..}, _) => MonsterType::PoisonLily,
(RawMapEnemy {id: 98, ..}, _) => MonsterType::NanoDragon,
(RawMapEnemy {id: 99, skin: 0, ..}, _) => MonsterType::EvilShark,
(RawMapEnemy {id: 99, skin: 1, ..}, _) => MonsterType::PalShark,
(RawMapEnemy {id: 99, skin: 2, ..}, _) => MonsterType::GuilShark,
(RawMapEnemy {id: 100, ..}, _) => MonsterType::PofuillySlime,
(RawMapEnemy {id: 101, ..}, _) => MonsterType::PanArms,
(RawMapEnemy {id: 128, skin: 0, ..}, _) => MonsterType::Dubchic,
(RawMapEnemy {id: 128, skin: 1, ..}, _) => MonsterType::Gillchic,
(RawMapEnemy {id: 129, ..}, _) => MonsterType::Garanz,
(RawMapEnemy {id: 130, field2: 0, ..}, _) => MonsterType::SinowBeat,
(RawMapEnemy {id: 130, ..}, _) => MonsterType::SinowGold,
(RawMapEnemy {id: 131, ..}, _) => MonsterType::Canadine,
(RawMapEnemy {id: 132, ..}, _) => MonsterType::Canane,
(RawMapEnemy {id: 133, ..}, _) => MonsterType::DubchicSwitch,
(RawMapEnemy {id: 160, ..}, _) => MonsterType::Delsaber,
(RawMapEnemy {id: 161, ..}, _) => MonsterType::ChaosSorcerer,
(RawMapEnemy {id: 162, ..}, _) => MonsterType::DarkGunner,
(RawMapEnemy {id: 164, ..}, _) => MonsterType::ChaosBringer,
(RawMapEnemy {id: 165, ..}, _) => MonsterType::DarkBelra,
(RawMapEnemy {id: 166, skin: 0, ..}, _) => MonsterType::Dimenian,
(RawMapEnemy {id: 166, skin: 1, ..}, _) => MonsterType::LaDimenian,
(RawMapEnemy {id: 166, skin: 2, ..}, _) => MonsterType::SoDimenian,
(RawMapEnemy {id: 167, ..}, _) => MonsterType::Bulclaw,
(RawMapEnemy {id: 168, ..}, _) => MonsterType::Claw,
(RawMapEnemy {id: 192, ..}, Episode::One) => MonsterType::Dragon,
(RawMapEnemy {id: 192, ..}, Episode::Two) => MonsterType::GalGryphon,
(RawMapEnemy {id: 193, ..}, _) => MonsterType::DeRolLe,
(RawMapEnemy {id: 194, ..}, _) => MonsterType::VolOptPartA,
(RawMapEnemy {id: 197, ..}, _) => MonsterType::VolOpt,
(RawMapEnemy {id: 200, ..}, _) => MonsterType::DarkFalz,
(RawMapEnemy {id: 202, ..}, _) => MonsterType::Olga,
(RawMapEnemy {id: 203, ..}, _) => MonsterType::BarbaRay,
(RawMapEnemy {id: 204, ..}, _) => MonsterType::GolDragon,
(RawMapEnemy {id: 212, skin: 0, ..}, _) => MonsterType::SinowBeril,
(RawMapEnemy {id: 212, skin: 1, ..}, _) => MonsterType::SinowSpigell,
(RawMapEnemy {id: 213, skin: 0, ..}, _) => MonsterType::Merillias,
(RawMapEnemy {id: 213, skin: 1, ..}, _) => MonsterType::Meriltas,
(RawMapEnemy {id: 214, skin: 0, ..}, _) => MonsterType::Mericarol,
(RawMapEnemy {id: 214, skin: 1, ..}, _) => MonsterType::Merikle,
(RawMapEnemy {id: 214, skin: 2, ..}, _) => MonsterType::Mericus,
(RawMapEnemy {id: 215, skin: 0, ..}, _) => MonsterType::UlGibbon,
(RawMapEnemy {id: 215, skin: 1, ..}, _) => MonsterType::ZolGibbon,
(RawMapEnemy {id: 216, ..}, _) => MonsterType::Gibbles,
(RawMapEnemy {id: 217, ..}, _) => MonsterType::Gee,
(RawMapEnemy {id: 218, ..}, _) => MonsterType::GiGue,
(RawMapEnemy {id: 219, ..}, _) => MonsterType::Deldepth,
(RawMapEnemy {id: 220, ..}, _) => MonsterType::Delbiter,
(RawMapEnemy {id: 221, skin: 0, ..}, _) => MonsterType::Dolmdarl,
(RawMapEnemy {id: 221, skin: 1, ..}, _) => MonsterType::Dolmolm,
(RawMapEnemy {id: 222, ..}, _) => MonsterType::Morfos,
(RawMapEnemy {id: 223, ..}, _) => MonsterType::ReconBox,
(RawMapEnemy {id: 224, ..}, _) => MonsterType::Epsilon,
(RawMapEnemy {id: 224, skin: 0, ..}, _) => MonsterType::SinowZoa,
(RawMapEnemy {id: 224, skin: 1, ..}, _) => MonsterType::SinowZele,
(RawMapEnemy {id: 225, ..}, _) => MonsterType::IllGill,
(RawMapEnemy {id: 272, ..}, _) => MonsterType::Astark,
(RawMapEnemy {id: 273, field2: 0, ..}, _) => MonsterType::SatelliteLizard,
(RawMapEnemy {id: 273, ..}, _) => MonsterType::Yowie,
(RawMapEnemy {id: 274, ..}, _) => MonsterType::MerissaA,
(RawMapEnemy {id: 275, ..}, _) => MonsterType::Girtablulu,
(RawMapEnemy {id: 276, ..}, _) => MonsterType::Zu,
(RawMapEnemy {id: 277, skin: 0, ..}, _) => MonsterType::Boota,
(RawMapEnemy {id: 277, skin: 1, ..}, _) => MonsterType::ZeBoota,
(RawMapEnemy {id: 277, skin: 2, ..}, _) => MonsterType::BaBoota,
(RawMapEnemy {id: 278, ..}, _) => MonsterType::Dorphon,
(RawMapEnemy {id: 279, skin: 0, ..}, _) => MonsterType::Goran,
(RawMapEnemy {id: 279, skin: 1, ..}, _) => MonsterType::PyroGoran,
(RawMapEnemy {id: 279, skin: 2, ..}, _) => MonsterType::GoranDetonator,
(RawMapEnemy {id: 281, skin: 0, ..}, _) => MonsterType::SaintMillion,
(RawMapEnemy {id: 281, skin: 1, ..}, _) => MonsterType::Shambertin,
_ => return Err(MapEnemyError::UnknownEnemyId(enemy.id))
2020-01-31 08:57:36 -08:00
};
2020-02-20 22:56:49 -08:00
Ok(MapEnemy {
2020-01-31 08:57:36 -08:00
monster: monster,
hp: 0,
dead: false,
2020-02-20 22:56:49 -08:00
})
2020-01-31 08:57:36 -08:00
}
fn new(monster: MonsterType) -> MapEnemy {
MapEnemy {
monster: monster,
hp: 0,
dead: false,
}
}
}
2020-03-28 12:04:51 -07:00
#[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,
})
}
}
2020-01-31 08:57:36 -08:00
#[derive(Debug)]
enum MapVariantMode {
Online,
Offline,
}
2020-01-31 08:57:36 -08:00
2020-03-14 10:44:27 -07:00
// TODO: rename this since apparently I'm going to be using it a lot
#[derive(Debug)]
2020-03-14 10:44:27 -07:00
pub enum MapVariantType {
Pioneer2Ep1,
Forest1,
Forest2,
Caves1,
Caves2,
Caves3,
Mines1,
Mines2,
Ruins1,
Ruins2,
Ruins3,
Dragon,
DeRolLe,
VolOpt,
DarkFalz,
}
2020-01-31 08:57:36 -08:00
2020-03-14 10:44:27 -07:00
impl MapVariantType {
pub fn area_value(&self) -> Option<u32> {
match self {
MapVariantType::Forest1 => Some(0),
MapVariantType::Forest2 => Some(1),
MapVariantType::Caves1 => Some(2),
MapVariantType::Caves2 => Some(3),
MapVariantType::Caves3 => Some(4),
MapVariantType::Mines1 => Some(5),
MapVariantType::Mines2 => Some(6),
MapVariantType::Ruins1 => Some(7),
MapVariantType::Ruins2 => Some(8),
MapVariantType::Ruins3 => Some(9),
MapVariantType::Dragon => Some(2),
MapVariantType::DeRolLe => Some(5),
MapVariantType::VolOpt => Some(7),
MapVariantType::DarkFalz => Some(9),
_ => None
}
}
}
2020-01-31 08:57:36 -08:00
#[derive(Debug)]
struct MapVariant {
map: MapVariantType,
mode: MapVariantMode,
major: u8,
minor: u8,
}
impl MapVariant {
fn new(map: MapVariantType, mode: MapVariantMode) -> MapVariant {
let major = match map {
MapVariantType::Pioneer2Ep1 => 0,
MapVariantType::Forest1 | MapVariantType::Forest2 => 0,
MapVariantType::Caves1 | MapVariantType::Caves2 | MapVariantType::Caves3 => rand::thread_rng().gen_range(0, 3),
MapVariantType::Mines1 | MapVariantType::Mines2 => rand::thread_rng().gen_range(0, 3),
MapVariantType::Ruins1 | MapVariantType::Ruins2 | MapVariantType::Ruins3 => rand::thread_rng().gen_range(0, 3),
MapVariantType::Dragon | MapVariantType::DeRolLe | MapVariantType::VolOpt | MapVariantType::DarkFalz => 0,
};
let minor = match map {
MapVariantType::Pioneer2Ep1 => 0,
MapVariantType::Forest1 => rand::thread_rng().gen_range(0, 6),
MapVariantType::Forest2 => rand::thread_rng().gen_range(0, 5),
MapVariantType::Caves1 | MapVariantType::Caves2 | MapVariantType::Caves3 => rand::thread_rng().gen_range(0, 2),
MapVariantType::Mines1 | MapVariantType::Mines2 => rand::thread_rng().gen_range(0, 2),
MapVariantType::Ruins1 | MapVariantType::Ruins2 | MapVariantType::Ruins3 => rand::thread_rng().gen_range(0, 2),
MapVariantType::Dragon | MapVariantType::DeRolLe | MapVariantType::VolOpt | MapVariantType::DarkFalz => 0,
};
MapVariant {
map: map,
mode: mode,
major: major,
minor: minor,
}
}
2020-03-28 12:04:51 -07:00
// TODO: rename to npc_file
fn dat_file(&self) -> String {
match self.map {
MapVariantType::Pioneer2Ep1 => "data/maps/map_city00_00e.dat".into(),
MapVariantType::Forest1 => format!("data/maps/map_forest01_0{}e.dat", self.minor),
MapVariantType::Forest2 => format!("data/maps/map_forest02_0{}e.dat", self.minor),
MapVariantType::Caves1 => format!("data/maps/map_cave01_0{}_0{}e.dat", self.major, self.minor),
MapVariantType::Caves2 => format!("data/maps/map_cave02_0{}_0{}e.dat", self.major, self.minor),
MapVariantType::Caves3 => format!("data/maps/map_cave03_0{}_0{}e.dat", self.major, self.minor),
MapVariantType::Mines1 => format!("data/maps/map_machine01_0{}_0{}e.dat", self.major, self.minor),
MapVariantType::Mines2 => format!("data/maps/map_machine02_0{}_0{}e.dat", self.major, self.minor),
MapVariantType::Ruins1 => format!("data/maps/map_ancient01_0{}_0{}e.dat", self.major, self.minor),
MapVariantType::Ruins2 => format!("data/maps/map_ancient02_0{}_0{}e.dat", self.major, self.minor),
MapVariantType::Ruins3 => format!("data/maps/map_ancient03_0{}_0{}e.dat", self.major, self.minor),
MapVariantType::Dragon => "data/maps/map_boss01e.dat".into(),
MapVariantType::DeRolLe => "data/maps/map_boss02e.dat".into(),
MapVariantType::VolOpt => "data/maps/map_boss03e.dat".into(),
MapVariantType::DarkFalz => "data/maps/map_boss04e.dat".into(),
}
}
2020-03-28 12:04:51 -07:00
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]
}
2020-01-31 08:57:36 -08:00
}
2020-03-28 12:04:51 -07:00
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();
while let Ok(enemy) = RawMapEnemy::from_byte_stream(&mut cursor) {
let new_enemy = MapEnemy::from_raw(enemy, episode);
enemy_data.append(&mut new_enemy
.map_or(vec![None], |monster| {
let mut monsters = Vec::new();
monsters.push(Some(monster));
match monster.monster {
MonsterType::Monest => {
for _ in 0..30 {
monsters.push(Some(MapEnemy::new(MonsterType::Mothmant)));
}
},
MonsterType::PofuillySlime => {
for _ in 0..4 {
monsters.push(Some(MapEnemy::new(MonsterType::PofuillySlime)));
}
},
MonsterType::PanArms => {
monsters.push(Some(MapEnemy::new(MonsterType::Hidoom)));
monsters.push(Some(MapEnemy::new(MonsterType::Migium)));
},
MonsterType::SinowBeat => {
for _ in 0..4 {
monsters.push(Some(MapEnemy::new(MonsterType::SinowBeat)));
}
},
MonsterType::SinowGold => {
for _ in 0..4 {
monsters.push(Some(MapEnemy::new(MonsterType::SinowGold)));
}
},
MonsterType::Canane => {
for _ in 0..8 {
monsters.push(Some(MapEnemy::new(MonsterType::RingCanadine)));
}
},
MonsterType::ChaosSorcerer => {
monsters.push(Some(MapEnemy::new(MonsterType::BeeR)));
monsters.push(Some(MapEnemy::new(MonsterType::BeeL)));
},
MonsterType::Bulclaw => {
for _ in 0..4 {
monsters.push(Some(MapEnemy::new(MonsterType::Claw)));
}
},
MonsterType::DeRolLe => {
for _ in 0..10 {
monsters.push(Some(MapEnemy::new(MonsterType::DeRolLeBody)));
}
for _ in 0..9 {
monsters.push(Some(MapEnemy::new(MonsterType::DeRolLeMine)));
}
},
MonsterType::VolOptPartA => {
for _ in 0..6 {
monsters.push(Some(MapEnemy::new(MonsterType::VolOptPillar)));
}
for _ in 0..24 {
monsters.push(Some(MapEnemy::new(MonsterType::VolOptMonitor)));
}
for _ in 0..2 {
monsters.push(Some(MapEnemy::new(MonsterType::VolOptUnused)));
}
monsters.push(Some(MapEnemy::new(MonsterType::VolOptAmp)));
monsters.push(Some(MapEnemy::new(MonsterType::VolOptCore)));
monsters.push(Some(MapEnemy::new(MonsterType::VolOptUnused)));
},
// TOOD: this cares about difficulty (theres an ult-specific darvant?)
MonsterType::DarkFalz => {
for _ in 0..509 {
monsters.push(Some(MapEnemy::new(MonsterType::Darvant)));
}
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz3)));
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz2)));
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz1)));
},
_ => {
for _ in 0..enemy.children {
monsters.push(Some(MapEnemy::new(monster.monster)));
}
}
}
monsters
}));
}
enemy_data
}
#[derive(Debug)]
pub struct Maps {
map_variants: [MapVariant; 15],
2020-03-28 12:04:51 -07:00
enemy_data: Vec<Option<MapEnemy>>,
object_data: Vec<Option<MapObject>>,
}
2020-01-31 08:57:36 -08:00
impl Maps {
pub fn new(episode: Episode) -> Maps {
let map_variants = match episode {
Episode::One => {
[MapVariant::new(MapVariantType::Pioneer2Ep1, MapVariantMode::Online),
MapVariant::new(MapVariantType::Forest1, MapVariantMode::Online),
MapVariant::new(MapVariantType::Forest2, MapVariantMode::Online),
MapVariant::new(MapVariantType::Caves1, MapVariantMode::Online),
MapVariant::new(MapVariantType::Caves2, MapVariantMode::Online),
MapVariant::new(MapVariantType::Caves3, MapVariantMode::Online),
MapVariant::new(MapVariantType::Mines1, MapVariantMode::Online),
MapVariant::new(MapVariantType::Mines2, MapVariantMode::Online),
MapVariant::new(MapVariantType::Ruins1, MapVariantMode::Online),
MapVariant::new(MapVariantType::Ruins2, MapVariantMode::Online),
MapVariant::new(MapVariantType::Ruins3, MapVariantMode::Online),
MapVariant::new(MapVariantType::Dragon, MapVariantMode::Online),
MapVariant::new(MapVariantType::DeRolLe, MapVariantMode::Online),
MapVariant::new(MapVariantType::VolOpt, MapVariantMode::Online),
MapVariant::new(MapVariantType::DarkFalz, MapVariantMode::Online),
]
},
_ => panic!()
};
2020-01-31 08:57:36 -08:00
let mut maps = Maps {
enemy_data: map_variants.iter().fold(Vec::new(), |mut enemy_data, map_variant| {
enemy_data.append(&mut enemy_data_from_map_data(map_variant.dat_file().into(), &episode));
enemy_data
}),
2020-03-28 12:04:51 -07:00
object_data: map_variants.iter().map(|map_variant| {
objects_from_map_data(map_variant.obj_file().into(), &episode)
}).flatten().collect(),
map_variants: map_variants,
2020-01-31 08:57:36 -08:00
};
maps
}
pub fn enemy_by_id(&self, id: usize) -> MapEnemy {
self.enemy_data[id].unwrap()
2020-01-31 08:57:36 -08:00
}
pub fn map_headers(&self) -> [u32; 0x20] {
self.map_variants.iter()
.enumerate()
.fold([0; 0x20], |mut header, (i, map_variant)| {
let [major, minor] = map_variant.pkt_header();
header[i*2] = major as u32;
header[i*2 + 1] = minor as u32;
header
})
2020-01-31 08:57:36 -08:00
}
}