jake
4 years ago
7 changed files with 1384 additions and 1289 deletions
-
1289src/ship/map.rs
-
220src/ship/map/area.rs
-
279src/ship/map/enemy.rs
-
317src/ship/map/maps.rs
-
25src/ship/map/mod.rs
-
174src/ship/map/object.rs
-
369src/ship/map/variant.rs
1289
src/ship/map.rs
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,220 @@ |
|||
// TOOD: `pub(super) for most of these?`
|
|||
|
|||
use std::convert::Into;
|
|||
use std::path::PathBuf;
|
|||
use std::io::{Read};
|
|||
use std::fs::File;
|
|||
|
|||
use byteorder::{LittleEndian, ReadBytesExt};
|
|||
use rand::Rng;
|
|||
use thiserror::Error;
|
|||
|
|||
use crate::ship::monster::MonsterType;
|
|||
use crate::ship::room::{Episode, RoomMode};
|
|||
|
|||
// TODO: don't use *
|
|||
use crate::ship::map::*;
|
|||
|
|||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|||
pub enum MapArea {
|
|||
Pioneer2Ep1,
|
|||
Forest1,
|
|||
Forest2,
|
|||
Caves1,
|
|||
Caves2,
|
|||
Caves3,
|
|||
Mines1,
|
|||
Mines2,
|
|||
Ruins1,
|
|||
Ruins2,
|
|||
Ruins3,
|
|||
Dragon,
|
|||
DeRolLe,
|
|||
VolOpt,
|
|||
DarkFalz,
|
|||
Pioneer2Ep2,
|
|||
VrTempleAlpha,
|
|||
VrTempleBeta,
|
|||
VrSpaceshipAlpha,
|
|||
VrSpaceshipBeta,
|
|||
Cca,
|
|||
JungleAreaNorth,
|
|||
JungleAreaEast,
|
|||
Mountain,
|
|||
Seaside,
|
|||
SeabedUpper,
|
|||
SeabedLower,
|
|||
GalGryphon,
|
|||
OlgaFlow,
|
|||
BarbaRay,
|
|||
GolDragon,
|
|||
SeasideNight,
|
|||
Tower,
|
|||
Pioneer2Ep4,
|
|||
CraterEast,
|
|||
CraterWest,
|
|||
CraterSouth,
|
|||
CraterNorth,
|
|||
CraterInterior,
|
|||
SubDesert1,
|
|||
SubDesert2,
|
|||
SubDesert3,
|
|||
SaintMillion,
|
|||
// TestMapEp4,
|
|||
}
|
|||
|
|||
#[derive(Error, Debug)]
|
|||
#[error("")]
|
|||
pub enum MapAreaError {
|
|||
UnknownMapArea(u16),
|
|||
}
|
|||
|
|||
impl MapArea {
|
|||
pub fn from_value(episode: &Episode, area: u16) -> Result<MapArea, MapAreaError> {
|
|||
match (episode, area) {
|
|||
(Episode::One, 0) => Ok(MapArea::Pioneer2Ep1),
|
|||
(Episode::One, 1) => Ok(MapArea::Forest1),
|
|||
(Episode::One, 2) => Ok(MapArea::Forest2),
|
|||
(Episode::One, 3) => Ok(MapArea::Caves1),
|
|||
(Episode::One, 4) => Ok(MapArea::Caves2),
|
|||
(Episode::One, 5) => Ok(MapArea::Caves3),
|
|||
(Episode::One, 6) => Ok(MapArea::Mines1),
|
|||
(Episode::One, 7) => Ok(MapArea::Mines2),
|
|||
(Episode::One, 8) => Ok(MapArea::Ruins1),
|
|||
(Episode::One, 9) => Ok(MapArea::Ruins2),
|
|||
(Episode::One, 10) => Ok(MapArea::Ruins3),
|
|||
(Episode::One, 11) => Ok(MapArea::Dragon),
|
|||
(Episode::One, 12) => Ok(MapArea::DeRolLe),
|
|||
(Episode::One, 13) => Ok(MapArea::VolOpt),
|
|||
(Episode::One, 14) => Ok(MapArea::DarkFalz),
|
|||
(Episode::Two, 0) => Ok(MapArea::Pioneer2Ep2),
|
|||
(Episode::Two, 1) => Ok(MapArea::VrTempleAlpha),
|
|||
(Episode::Two, 2) => Ok(MapArea::VrTempleBeta),
|
|||
(Episode::Two, 3) => Ok(MapArea::VrSpaceshipAlpha),
|
|||
(Episode::Two, 4) => Ok(MapArea::VrSpaceshipBeta),
|
|||
(Episode::Two, 5) => Ok(MapArea::Cca),
|
|||
(Episode::Two, 6) => Ok(MapArea::JungleAreaNorth),
|
|||
(Episode::Two, 7) => Ok(MapArea::JungleAreaEast),
|
|||
(Episode::Two, 8) => Ok(MapArea::Mountain),
|
|||
(Episode::Two, 9) => Ok(MapArea::Seaside),
|
|||
(Episode::Two, 10) => Ok(MapArea::SeabedUpper),
|
|||
(Episode::Two, 11) => Ok(MapArea::SeabedLower),
|
|||
(Episode::Two, 12) => Ok(MapArea::GalGryphon),
|
|||
(Episode::Two, 13) => Ok(MapArea::OlgaFlow),
|
|||
(Episode::Two, 14) => Ok(MapArea::BarbaRay),
|
|||
(Episode::Two, 15) => Ok(MapArea::GolDragon),
|
|||
(Episode::Two, 16) => Ok(MapArea::SeasideNight),
|
|||
(Episode::Two, 17) => Ok(MapArea::Tower),
|
|||
(Episode::Four, 0) => Ok(MapArea::Pioneer2Ep4),
|
|||
(Episode::Four, 1) => Ok(MapArea::CraterEast),
|
|||
(Episode::Four, 2) => Ok(MapArea::CraterWest),
|
|||
(Episode::Four, 3) => Ok(MapArea::CraterSouth),
|
|||
(Episode::Four, 4) => Ok(MapArea::CraterNorth),
|
|||
(Episode::Four, 5) => Ok(MapArea::CraterInterior),
|
|||
(Episode::Four, 6) => Ok(MapArea::SubDesert1),
|
|||
(Episode::Four, 7) => Ok(MapArea::SubDesert2),
|
|||
(Episode::Four, 8) => Ok(MapArea::SubDesert3),
|
|||
(Episode::Four, 9) => Ok(MapArea::SaintMillion),
|
|||
// (Episode::Four, 10) => Ok(MapArea::TestMapEp4),
|
|||
_ => Err(MapAreaError::UnknownMapArea(area))
|
|||
}
|
|||
}
|
|||
|
|||
pub fn drop_area_value(&self) -> Option<u32> {
|
|||
match self {
|
|||
MapArea::Forest1 => Some(0),
|
|||
MapArea::Forest2 => Some(1),
|
|||
MapArea::Caves1 => Some(2),
|
|||
MapArea::Caves2 => Some(3),
|
|||
MapArea::Caves3 => Some(4),
|
|||
MapArea::Mines1 => Some(5),
|
|||
MapArea::Mines2 => Some(6),
|
|||
MapArea::Ruins1 => Some(7),
|
|||
MapArea::Ruins2 => Some(8),
|
|||
MapArea::Ruins3 => Some(9),
|
|||
MapArea::Dragon => Some(2),
|
|||
MapArea::DeRolLe => Some(5),
|
|||
MapArea::VolOpt => Some(7),
|
|||
MapArea::DarkFalz => Some(9),
|
|||
|
|||
MapArea::VrTempleAlpha => Some(0),
|
|||
MapArea::VrTempleBeta => Some(1),
|
|||
MapArea::VrSpaceshipAlpha => Some(2),
|
|||
MapArea::VrSpaceshipBeta => Some(3),
|
|||
MapArea::Cca => Some(4),
|
|||
MapArea::JungleAreaNorth => Some(5),
|
|||
MapArea::JungleAreaEast => Some(5),
|
|||
MapArea::Mountain => Some(6),
|
|||
MapArea::Seaside => Some(7),
|
|||
MapArea::SeabedUpper => Some(8),
|
|||
MapArea::SeabedLower => Some(9),
|
|||
MapArea::GalGryphon => Some(8),
|
|||
MapArea::OlgaFlow => Some(9),
|
|||
MapArea::BarbaRay => Some(2),
|
|||
MapArea::GolDragon => Some(5),
|
|||
MapArea::SeasideNight => Some(7),
|
|||
MapArea::Tower => Some(9),
|
|||
|
|||
MapArea::CraterEast => Some(2),
|
|||
MapArea::CraterWest => Some(3),
|
|||
MapArea::CraterSouth => Some(4),
|
|||
MapArea::CraterNorth => Some(5),
|
|||
MapArea::CraterInterior => Some(6),
|
|||
MapArea::SubDesert1 => Some(7),
|
|||
MapArea::SubDesert2 => Some(8),
|
|||
MapArea::SubDesert3 => Some(9),
|
|||
MapArea::SaintMillion => Some(9),
|
|||
// MapArea::TestMapEp4 => Some(0),
|
|||
_ => None
|
|||
}
|
|||
}
|
|||
|
|||
pub fn area_value(&self) -> u8 {
|
|||
match self {
|
|||
MapArea::Pioneer2Ep1 => 0,
|
|||
MapArea::Forest1 => 1,
|
|||
MapArea::Forest2 => 2,
|
|||
MapArea::Caves1 => 3,
|
|||
MapArea::Caves2 => 4,
|
|||
MapArea::Caves3 => 5,
|
|||
MapArea::Mines1 => 6,
|
|||
MapArea::Mines2 => 7,
|
|||
MapArea::Ruins1 => 8,
|
|||
MapArea::Ruins2 => 9,
|
|||
MapArea::Ruins3 => 10,
|
|||
MapArea::Dragon => 11,
|
|||
MapArea::DeRolLe => 12,
|
|||
MapArea::VolOpt => 13,
|
|||
MapArea::DarkFalz => 14,
|
|||
MapArea::Pioneer2Ep2 => 0,
|
|||
MapArea::VrTempleAlpha => 1,
|
|||
MapArea::VrTempleBeta => 2,
|
|||
MapArea::VrSpaceshipAlpha => 3,
|
|||
MapArea::VrSpaceshipBeta => 4,
|
|||
MapArea::Cca => 5,
|
|||
MapArea::JungleAreaNorth => 6,
|
|||
MapArea::JungleAreaEast => 7,
|
|||
MapArea::Mountain => 8,
|
|||
MapArea::Seaside => 9,
|
|||
MapArea::SeabedUpper => 10,
|
|||
MapArea::SeabedLower => 11,
|
|||
MapArea::GalGryphon => 12,
|
|||
MapArea::OlgaFlow => 13,
|
|||
MapArea::BarbaRay => 14,
|
|||
MapArea::GolDragon => 15,
|
|||
MapArea::SeasideNight => 16,
|
|||
MapArea::Tower => 17,
|
|||
MapArea::Pioneer2Ep4 => 0,
|
|||
MapArea::CraterEast => 1,
|
|||
MapArea::CraterWest => 2,
|
|||
MapArea::CraterSouth => 3,
|
|||
MapArea::CraterNorth => 4,
|
|||
MapArea::CraterInterior => 5,
|
|||
MapArea::SubDesert1 => 6,
|
|||
MapArea::SubDesert2 => 7,
|
|||
MapArea::SubDesert3 => 8,
|
|||
MapArea::SaintMillion => 9,
|
|||
// MapArea::TestMapEp4 => 10,
|
|||
}
|
|||
}
|
|||
}
|
@ -0,0 +1,279 @@ |
|||
// TOOD: `pub(super) for most of these?`
|
|||
use std::convert::Into;
|
|||
use std::path::PathBuf;
|
|||
use std::io::{Read};
|
|||
use std::fs::File;
|
|||
|
|||
use byteorder::{LittleEndian, ReadBytesExt};
|
|||
use rand::Rng;
|
|||
use thiserror::Error;
|
|||
|
|||
use crate::ship::monster::MonsterType;
|
|||
use crate::ship::room::{Episode, RoomMode};
|
|||
|
|||
use crate::ship::map::*;
|
|||
|
|||
#[derive(Debug, Copy, Clone)]
|
|||
pub struct RawMapEnemy {
|
|||
id: u32,
|
|||
_unknown1: u16,
|
|||
pub children: u16,
|
|||
map_area: u16,
|
|||
_unknown4: u16,
|
|||
section: u16,
|
|||
wave_idd: u16,
|
|||
wave_id: u32,
|
|||
x: f32,
|
|||
y: f32,
|
|||
z: f32,
|
|||
xrot: u32,
|
|||
yrot: u32,
|
|||
zrot: u32,
|
|||
_field1: u32,
|
|||
field2: u32,
|
|||
_field3: u32,
|
|||
_field4: u32,
|
|||
_field5: u32,
|
|||
skin: u32,
|
|||
_field6: u32 |
|||
}
|
|||
|
|||
impl RawMapEnemy {
|
|||
pub 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>()?,
|
|||
map_area: 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>()?,
|
|||
_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>()?,
|
|||
skin: cursor.read_u32::<LittleEndian>()?,
|
|||
_field6: cursor.read_u32::<LittleEndian>()?,
|
|||
})
|
|||
}
|
|||
}
|
|||
|
|||
|
|||
#[derive(Error, Debug)]
|
|||
#[error("")]
|
|||
pub enum MapEnemyError {
|
|||
UnknownEnemyId(u32),
|
|||
MapAreaError(#[from] MapAreaError),
|
|||
}
|
|||
|
|||
|
|||
#[derive(Debug, Copy, Clone)]
|
|||
pub struct MapEnemy {
|
|||
pub monster: MonsterType,
|
|||
pub map_area: MapArea,
|
|||
hp: u32,
|
|||
// TODO: other stats from battleparam
|
|||
pub player_hit: [bool; 4],
|
|||
pub dropped_item: bool,
|
|||
pub gave_exp: bool,
|
|||
}
|
|||
|
|||
impl MapEnemy {
|
|||
pub fn from_raw(enemy: RawMapEnemy, episode: &Episode, map_area: &MapArea /*, battleparam */) -> Result<MapEnemy, MapEnemyError> {
|
|||
// TODO: rare enemies ep1-4, tower lilys, event rappies, ult variants?
|
|||
let monster = match map_area {
|
|||
MapArea::Forest1 | MapArea::Forest2 | MapArea::Dragon |
|
|||
MapArea::Caves1 | MapArea::Caves2 | MapArea::Caves3 | MapArea::DeRolLe |
|
|||
MapArea::Mines1 | MapArea::Mines2 | MapArea::VolOpt |
|
|||
MapArea::Ruins1 | MapArea::Ruins2 | MapArea::Ruins3 | MapArea::DarkFalz => {
|
|||
match (enemy, episode) {
|
|||
(RawMapEnemy {id: 64, ..}, _) => MonsterType::Hildebear,
|
|||
// (RawMapEnemy {id: 64, ..}, _) => MonsterType::Hildeblue,
|
|||
(RawMapEnemy {id: 65, ..}, _) => MonsterType::RagRappy,
|
|||
// (RawMapEnemy {id: 65, ..}, _) => MonsterType::AlRappy,
|
|||
(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, ..}, _) => MonsterType::PoisonLily,
|
|||
// (RawMapEnemy {id: 97, ..}, _) => MonsterType::NarLily,
|
|||
(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: 100, ..}, _) => MonsterType::PouillySlime,
|
|||
(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::Dubwitch,
|
|||
(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: 193, ..}, _) => MonsterType::DeRolLe,
|
|||
(RawMapEnemy {id: 194, ..}, _) => MonsterType::VolOptPartA,
|
|||
(RawMapEnemy {id: 197, ..}, _) => MonsterType::VolOpt,
|
|||
(RawMapEnemy {id: 200, ..}, _) => MonsterType::DarkFalz,
|
|||
_ => return Err(MapEnemyError::UnknownEnemyId(enemy.id))
|
|||
}
|
|||
},
|
|||
|
|||
MapArea::VrTempleAlpha | MapArea::VrTempleBeta | MapArea::BarbaRay |
|
|||
MapArea::VrSpaceshipAlpha | MapArea::VrSpaceshipBeta | MapArea::GolDragon |
|
|||
MapArea::JungleAreaNorth | MapArea::JungleAreaEast | MapArea::Mountain | MapArea::Seaside | MapArea::SeasideNight | MapArea::Cca | MapArea::GalGryphon |
|
|||
MapArea::SeabedUpper | MapArea::SeabedLower | MapArea::OlgaFlow => {
|
|||
match (enemy, episode) {
|
|||
(RawMapEnemy {id: 64, ..}, _) => MonsterType::Hildebear,
|
|||
// (RawMapEnemy {id: 64, ..}, _) => MonsterType::Hildeblue,
|
|||
(RawMapEnemy {id: 65, ..}, _) => MonsterType::RagRappy,
|
|||
// (RawMapEnemy {id: 65, ..}, _) => MonsterType::EventRappy,
|
|||
(RawMapEnemy {id: 66, ..}, _) => MonsterType::Monest,
|
|||
(RawMapEnemy {id: 67, field2: 0, ..}, _) => MonsterType::SavageWolf,
|
|||
(RawMapEnemy {id: 67, ..}, _) => MonsterType::BarbarousWolf,
|
|||
(RawMapEnemy {id: 96, ..}, _) => MonsterType::GrassAssassin,
|
|||
(RawMapEnemy {id: 97, ..}, _) => MonsterType::PoisonLily,
|
|||
// (RawMapEnemy {id: 97, ..}, _) => MonsterType::NarLily,
|
|||
// (RawMapEnemy {id: 97, ..}, _) => MonsterType::DelLily,
|
|||
(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: 133, ..}, _) => MonsterType::Dubwitch,
|
|||
(RawMapEnemy {id: 160, ..}, _) => MonsterType::Delsaber,
|
|||
(RawMapEnemy {id: 161, ..}, _) => MonsterType::ChaosSorcerer,
|
|||
(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: 192, ..}, Episode::Two) => MonsterType::GalGryphon,
|
|||
(RawMapEnemy {id: 202, ..}, _) => MonsterType::OlgaFlow,
|
|||
(RawMapEnemy {id: 203, ..}, _) => MonsterType::BarbaRay,
|
|||
(RawMapEnemy {id: 204, ..}, _) => MonsterType::GolDragon,
|
|||
(RawMapEnemy {id: 212, skin: 0, ..}, _) => MonsterType::SinowBerill,
|
|||
(RawMapEnemy {id: 212, skin: 1, ..}, _) => MonsterType::SinowSpigell,
|
|||
(RawMapEnemy {id: 213, skin: 0, ..}, _) => MonsterType::Merillia,
|
|||
(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::Dolmolm,
|
|||
(RawMapEnemy {id: 221, skin: 1, ..}, _) => MonsterType::Dolmdarl,
|
|||
(RawMapEnemy {id: 222, ..}, _) => MonsterType::Morfos,
|
|||
(RawMapEnemy {id: 223, ..}, _) => MonsterType::Recobox,
|
|||
(RawMapEnemy {id: 224, skin: 0, ..}, _) => MonsterType::SinowZoa,
|
|||
(RawMapEnemy {id: 224, skin: 1, ..}, _) => MonsterType::SinowZele,
|
|||
(RawMapEnemy {id: 224, ..}, _) => MonsterType::Epsilon,
|
|||
(RawMapEnemy {id: 225, ..}, _) => MonsterType::IllGill,
|
|||
_ => return Err(MapEnemyError::UnknownEnemyId(enemy.id))
|
|||
}
|
|||
},
|
|||
|
|||
MapArea::Tower => {
|
|||
match (enemy, episode) {
|
|||
(RawMapEnemy {id: 97, ..}, _) => MonsterType::DelLily,
|
|||
(RawMapEnemy {id: 214, skin: 0, ..}, _) => MonsterType::Mericarol,
|
|||
(RawMapEnemy {id: 214, skin: 1, ..}, _) => MonsterType::Merikle,
|
|||
(RawMapEnemy {id: 214, skin: 2, ..}, _) => MonsterType::Mericus,
|
|||
(RawMapEnemy {id: 216, ..}, _) => MonsterType::Gibbles,
|
|||
(RawMapEnemy {id: 218, ..}, _) => MonsterType::GiGue,
|
|||
(RawMapEnemy {id: 220, ..}, _) => MonsterType::Delbiter,
|
|||
(RawMapEnemy {id: 223, ..}, _) => MonsterType::Recobox,
|
|||
(RawMapEnemy {id: 224, ..}, _) => MonsterType::Epsilon,
|
|||
(RawMapEnemy {id: 225, ..}, _) => MonsterType::IllGill,
|
|||
_ => return Err(MapEnemyError::UnknownEnemyId(enemy.id))
|
|||
}
|
|||
},
|
|||
|
|||
MapArea::CraterEast | MapArea::CraterWest | MapArea::CraterSouth | MapArea::CraterNorth | MapArea::CraterInterior => {
|
|||
match (enemy, episode) {
|
|||
(RawMapEnemy {id: 65, ..}, Episode::Four) => MonsterType::SandRappyCrater,
|
|||
// (RawMapEnemy {id: 65, ..}, Episode::Four) => MonsterType::DelRappyCrater,
|
|||
(RawMapEnemy {id: 272, ..}, _) => MonsterType::Astark,
|
|||
(RawMapEnemy {id: 273, field2: 0, ..}, _) => MonsterType::SatelliteLizardCrater,
|
|||
(RawMapEnemy {id: 273, ..}, _) => MonsterType::YowieCrater,
|
|||
(RawMapEnemy {id: 276, ..}, _) => MonsterType::ZuCrater,
|
|||
// (RawMapEnemy {id: 276, ..}, _) => MonsterType::PazuzuCrater,
|
|||
(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: 278, ..}, _) => MonsterType::DorphonEclair,
|
|||
_ => return Err(MapEnemyError::UnknownEnemyId(enemy.id))
|
|||
}
|
|||
},
|
|||
MapArea::SubDesert1 | MapArea::SubDesert2 | MapArea::SubDesert3 | MapArea::SaintMillion => {
|
|||
match (enemy, episode) {
|
|||
(RawMapEnemy {id: 65, ..}, Episode::Four) => MonsterType::SandRappyDesert,
|
|||
// (RawMapEnemy {id: 65, ..}, Episode::Four) => MonsterType::DelRappyDesert,
|
|||
(RawMapEnemy {id: 273, field2: 0, ..}, _) => MonsterType::SatelliteLizardDesert,
|
|||
(RawMapEnemy {id: 273, ..}, _) => MonsterType::YowieDesert,
|
|||
(RawMapEnemy {id: 274, ..}, _) => MonsterType::MerissaA,
|
|||
// (RawMapEnemy {id: 274, ..}, _) => MonsterType::MerissaAA,
|
|||
(RawMapEnemy {id: 275, ..}, _) => MonsterType::Girtablulu,
|
|||
(RawMapEnemy {id: 276, ..}, _) => MonsterType::ZuDesert,
|
|||
// (RawMapEnemy {id: 276, ..}, _) => MonsterType::PazuzuDesert,
|
|||
(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,
|
|||
// (RawMapEnemy {id: 281, skin: 1, ..}, _) => MonsterType::Kondrieu,
|
|||
_ => return Err(MapEnemyError::UnknownEnemyId(enemy.id))
|
|||
}
|
|||
},
|
|||
_ => return Err(MapEnemyError::UnknownEnemyId(enemy.id))
|
|||
};
|
|||
|
|||
Ok(MapEnemy {
|
|||
monster: monster,
|
|||
map_area: map_area.clone(),
|
|||
hp: 0,
|
|||
dropped_item: false,
|
|||
gave_exp: false,
|
|||
player_hit: [false; 4],
|
|||
})
|
|||
}
|
|||
|
|||
pub fn new(monster: MonsterType, map_area: MapArea) -> MapEnemy {
|
|||
MapEnemy {
|
|||
monster: monster,
|
|||
map_area: map_area,
|
|||
hp: 0,
|
|||
dropped_item: false,
|
|||
gave_exp: false,
|
|||
player_hit: [false; 4],
|
|||
}
|
|||
}
|
|||
}
|
|||
|
@ -0,0 +1,317 @@ |
|||
// TOOD: `pub(super) for most of these?`
|
|||
|
|||
use std::convert::Into;
|
|||
use std::path::PathBuf;
|
|||
use std::io::{Read};
|
|||
use std::fs::File;
|
|||
|
|||
use byteorder::{LittleEndian, ReadBytesExt};
|
|||
use rand::Rng;
|
|||
use thiserror::Error;
|
|||
|
|||
use crate::ship::monster::MonsterType;
|
|||
use crate::ship::room::{Episode, RoomMode};
|
|||
|
|||
// TODO: don't use *
|
|||
use crate::ship::map::*;
|
|||
|
|||
|
|||
pub fn objects_from_stream(cursor: &mut impl Read, episode: &Episode, map_area: &MapArea) -> Vec<Option<MapObject>> {
|
|||
let mut object_data = Vec::new();
|
|||
|
|||
while let Ok(raw_object) = RawMapObject::from_byte_stream(cursor) {
|
|||
let object = MapObject::from_raw(raw_object.clone(), *episode, map_area);
|
|||
object_data.push(object.ok());
|
|||
}
|
|||
object_data
|
|||
}
|
|||
|
|||
fn objects_from_map_data(path: PathBuf, episode: &Episode, map_area: &MapArea) -> Vec<Option<MapObject>> {
|
|||
let mut cursor = File::open(path.clone()).unwrap();
|
|||
objects_from_stream(&mut cursor, episode, map_area)
|
|||
}
|
|||
|
|||
fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) -> Vec<Option<MapEnemy>> {
|
|||
let enemy = MapEnemy::from_raw(raw_enemy, episode, map_area);
|
|||
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, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::PofuillySlime => {
|
|||
for _ in 0..4 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::PofuillySlime, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::PanArms => {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::Hidoom, monster.map_area)));
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::Migium, monster.map_area)));
|
|||
},
|
|||
MonsterType::SinowBeat => {
|
|||
for _ in 0..4 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::SinowBeat, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::SinowGold => {
|
|||
for _ in 0..4 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::SinowGold, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::Canane => {
|
|||
for _ in 0..8 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::RingCanadine, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::ChaosSorcerer => {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::BeeR, monster.map_area)));
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::BeeL, monster.map_area)));
|
|||
},
|
|||
MonsterType::Bulclaw => {
|
|||
for _ in 0..4 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::Claw, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::DeRolLe => {
|
|||
for _ in 0..10 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::DeRolLeBody, monster.map_area)));
|
|||
}
|
|||
for _ in 0..9 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::DeRolLeMine, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::VolOptPartA => {
|
|||
for _ in 0..6 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptPillar, monster.map_area)));
|
|||
}
|
|||
for _ in 0..24 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptMonitor, monster.map_area)));
|
|||
}
|
|||
for _ in 0..2 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptUnused, monster.map_area)));
|
|||
}
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptAmp, monster.map_area)));
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptCore, monster.map_area)));
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptUnused, monster.map_area)));
|
|||
},
|
|||
// TOOD: this cares about difficulty (theres an ult-specific darvant?)
|
|||
MonsterType::DarkFalz => {
|
|||
for _ in 0..509 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::Darvant, monster.map_area)));
|
|||
}
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz3, monster.map_area)));
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz2, monster.map_area)));
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz1, monster.map_area)));
|
|||
},
|
|||
MonsterType::OlgaFlow => {
|
|||
for _ in 0..512 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::OlgaFlow, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::BarbaRay => {
|
|||
for _ in 0..47 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::PigRay, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::GolDragon => {
|
|||
for _ in 0..5 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::GolDragon, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::SinowBerill => {
|
|||
for _ in 0..4 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::SinowBerill, monster.map_area))); // unused clones
|
|||
}
|
|||
},
|
|||
MonsterType::SinowSpigell => {
|
|||
for _ in 0..4 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::SinowSpigell, monster.map_area))); // unused clones
|
|||
}
|
|||
},
|
|||
MonsterType::Recobox => { // + recons
|
|||
for _ in 0..raw_enemy.children {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::Recon, monster.map_area)));
|
|||
}
|
|||
},
|
|||
MonsterType::Epsilon => {
|
|||
for _ in 0..4 {
|
|||
monsters.push(Some(MapEnemy::new(MonsterType::Epsiguard, monster.map_area)));
|
|||
}
|
|||
},
|
|||
_ => {
|
|||
for _ in 0..raw_enemy.children {
|
|||
monsters.push(Some(MapEnemy::new(monster.monster, monster.map_area)));
|
|||
}
|
|||
}
|
|||
}
|
|||
monsters
|
|||
})
|
|||
}
|
|||
|
|||
|
|||
pub fn enemy_data_from_stream(cursor: &mut impl Read, map_area: &MapArea, episode: &Episode) -> Vec<Option<MapEnemy>> {
|
|||
let mut enemy_data = Vec::new();
|
|||
while let Ok(enemy) = RawMapEnemy::from_byte_stream(cursor) {
|
|||
enemy_data.append(&mut parse_enemy(episode, map_area, enemy));
|
|||
}
|
|||
enemy_data
|
|||
}
|
|||
|
|||
fn enemy_data_from_map_data(map_variant: &MapVariant, episode: &Episode) -> Vec<Option<MapEnemy>> {
|
|||
let path = map_variant.dat_file();
|
|||
let mut cursor = File::open(path).unwrap();
|
|||
enemy_data_from_stream(&mut cursor, &map_variant.map, episode)
|
|||
}
|
|||
|
|||
|
|||
#[derive(Error, Debug)]
|
|||
#[error("")]
|
|||
pub enum MapsError {
|
|||
InvalidMonsterId(usize),
|
|||
InvalidObjectId(usize),
|
|||
}
|
|||
|
|||
#[derive(Debug)]
|
|||
pub struct Maps {
|
|||
map_variants: Vec<MapVariant>,
|
|||
enemy_data: Vec<Option<MapEnemy>>,
|
|||
object_data: Vec<Option<MapObject>>,
|
|||
}
|
|||
|
|||
impl Maps {
|
|||
pub fn new(room_mode: RoomMode) -> Maps {
|
|||
let map_variants = match (room_mode.episode(), room_mode.single_player()) {
|
|||
(Episode::One, 0) => {
|
|||
vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Forest1, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Forest2, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Caves1, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Caves2, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Caves3, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Mines1, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Mines2, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Ruins1, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Ruins2, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Ruins3, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Dragon, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::DeRolLe, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::VolOpt, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::DarkFalz, MapVariantMode::Online),
|
|||
]
|
|||
},
|
|||
(Episode::One, 1) => {
|
|||
vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Forest1, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Forest2, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Caves1, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Caves2, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Caves3, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Mines1, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Mines2, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Ruins1, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Ruins2, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Ruins3, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Dragon, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::DeRolLe, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::VolOpt, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::DarkFalz, MapVariantMode::Offline),
|
|||
]
|
|||
},
|
|||
(Episode::Two, 0) => {
|
|||
vec![MapVariant::new(MapArea::Pioneer2Ep2, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::VrTempleAlpha, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::VrTempleBeta, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::VrSpaceshipAlpha, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::VrSpaceshipBeta, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Cca, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::JungleAreaNorth, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::JungleAreaEast, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Mountain, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::Seaside, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::SeabedUpper, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::SeabedLower, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::GalGryphon, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::OlgaFlow, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::BarbaRay, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::GolDragon, MapVariantMode::Online),
|
|||
]
|
|||
},
|
|||
(Episode::Two, 1) => {
|
|||
vec![MapVariant::new(MapArea::Pioneer2Ep2, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::VrTempleAlpha, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::VrTempleBeta, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::VrSpaceshipAlpha, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::VrSpaceshipBeta, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Cca, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::JungleAreaNorth, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::JungleAreaEast, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Mountain, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::Seaside, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::SeabedUpper, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::SeabedLower, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::GalGryphon, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::OlgaFlow, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::BarbaRay, MapVariantMode::Offline),
|
|||
MapVariant::new(MapArea::GolDragon, MapVariantMode::Offline),
|
|||
]
|
|||
},
|
|||
(Episode::Four, _) => {
|
|||
vec![MapVariant::new(MapArea::Pioneer2Ep4, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::CraterEast, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::CraterWest, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::CraterSouth, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::CraterNorth, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::CraterInterior, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::SubDesert1, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::SubDesert2, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::SubDesert3, MapVariantMode::Online),
|
|||
MapVariant::new(MapArea::SaintMillion, MapVariantMode::Online),
|
|||
]
|
|||
},
|
|||
_ => unreachable!()
|
|||
};
|
|||
|
|||
let 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, &room_mode.episode()));
|
|||
enemy_data
|
|||
}),
|
|||
object_data: map_variants.iter().map(|map_variant| {
|
|||
objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map)
|
|||
}).flatten().collect(),
|
|||
map_variants: map_variants,
|
|||
};
|
|||
maps
|
|||
}
|
|||
|
|||
pub fn enemy_by_id(&self, id: usize) -> Result<MapEnemy, MapsError> {
|
|||
self.enemy_data[id].ok_or(MapsError::InvalidMonsterId(id))
|
|||
}
|
|||
|
|||
pub fn object_by_id(&self, id: usize) -> Result<MapObject, MapsError> {
|
|||
self.object_data[id].ok_or(MapsError::InvalidObjectId(id))
|
|||
}
|
|||
|
|||
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
|
|||
})
|
|||
}
|
|||
|
|||
pub fn set_quest_data(&mut self, enemies: Vec<Option<MapEnemy>>, objects: Vec<Option<MapObject>>) {
|
|||
self.enemy_data = enemies;
|
|||
self.object_data = objects;
|
|||
}
|
|||
}
|
|||
|
@ -0,0 +1,25 @@ |
|||
mod area;
|
|||
mod enemy;
|
|||
mod object;
|
|||
mod variant;
|
|||
mod maps;
|
|||
|
|||
// TODO: don't just forward everything to the module scope
|
|||
pub use area::*;
|
|||
pub use enemy::*;
|
|||
pub use object::*;
|
|||
pub use variant::*;
|
|||
pub use maps::*;
|
|||
|
|||
use std::convert::Into;
|
|||
use std::path::PathBuf;
|
|||
use std::io::{Read};
|
|||
use std::fs::File;
|
|||
|
|||
use byteorder::{LittleEndian, ReadBytesExt};
|
|||
use rand::Rng;
|
|||
use thiserror::Error;
|
|||
|
|||
use crate::ship::monster::MonsterType;
|
|||
use crate::ship::room::{Episode, RoomMode};
|
|||
|
@ -0,0 +1,174 @@ |
|||
// TOOD: `pub(super) for most of these?`
|
|||
|
|||
use std::convert::Into;
|
|||
use std::path::PathBuf;
|
|||
use std::io::{Read};
|
|||
use std::fs::File;
|
|||
|
|||
use byteorder::{LittleEndian, ReadBytesExt};
|
|||
use rand::Rng;
|
|||
use thiserror::Error;
|
|||
|
|||
use crate::ship::monster::MonsterType;
|
|||
use crate::ship::room::{Episode, RoomMode};
|
|||
|
|||
// 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,
|
|||
}
|
|||
|
|||
#[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: 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,
|
|||
(RawMapObject {otype: 512, ..}, _) => MapObjectType::CcaBox,
|
|||
(RawMapObject {otype: 515, ..}, _) => MapObjectType::CcaFixedBox(FixedBoxDropType::from_object(raw.field1, raw.field2, raw.field3, raw.field4)),
|
|||
_ => return Err(MapObjectError::UnknownObjectType(raw.otype, raw))
|
|||
};
|
|||
|
|||
Ok(MapObject {
|
|||
object: object,
|
|||
map: map_area.clone(),
|
|||
dropped_item: false,
|
|||
})
|
|||
}
|
|||
}
|
|||
|
@ -0,0 +1,369 @@ |
|||
// TOOD: `pub(super) for most of these?`
|
|||
|
|||
use std::convert::Into;
|
|||
use std::path::PathBuf;
|
|||
use std::io::{Read};
|
|||
use std::fs::File;
|
|||
|
|||
use byteorder::{LittleEndian, ReadBytesExt};
|
|||
use rand::Rng;
|
|||
use thiserror::Error;
|
|||
|
|||
use crate::ship::monster::MonsterType;
|
|||
use crate::ship::room::{Episode, RoomMode};
|
|||
|
|||
// TODO: don't use *
|
|||
use crate::ship::map::*;
|
|||
|
|||
#[derive(Debug, PartialEq)]
|
|||
pub enum MapVariantMode {
|
|||
Online,
|
|||
Offline,
|
|||
}
|
|||
|
|||
#[derive(Debug)]
|
|||
pub struct MapVariant {
|
|||
pub map: MapArea,
|
|||
mode: MapVariantMode,
|
|||
major: u8,
|
|||
minor: u8,
|
|||
}
|
|||
|
|||
impl MapVariant {
|
|||
pub fn new(map: MapArea, mode: MapVariantMode) -> MapVariant {
|
|||
if mode == MapVariantMode::Online {
|
|||
let major = match map {
|
|||
MapArea::Pioneer2Ep1 => 0,
|
|||
MapArea::Forest1 | MapArea::Forest2 => 0,
|
|||
MapArea::Caves1 | MapArea::Caves2 | MapArea::Caves3 => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::Mines1 | MapArea::Mines2 => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::Ruins1 | MapArea::Ruins2 | MapArea::Ruins3 => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::Dragon | MapArea::DeRolLe | MapArea::VolOpt | MapArea::DarkFalz => 0,
|
|||
|
|||
MapArea::Pioneer2Ep2 => 0,
|
|||
MapArea::VrTempleAlpha | MapArea::VrTempleBeta => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::VrSpaceshipAlpha | MapArea::VrSpaceshipBeta => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Cca => 0,
|
|||
MapArea::JungleAreaNorth | MapArea::JungleAreaEast => 0,
|
|||
MapArea::Mountain => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Seaside | MapArea::SeasideNight=> 0,
|
|||
MapArea::SeabedUpper | MapArea::SeabedLower => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::BarbaRay | MapArea::GolDragon | MapArea::GalGryphon | MapArea::OlgaFlow => 0,
|
|||
MapArea::Tower => 0,
|
|||
|
|||
MapArea::Pioneer2Ep4 => 0,
|
|||
MapArea::CraterEast | MapArea::CraterWest | MapArea::CraterSouth | MapArea::CraterNorth | MapArea::CraterInterior => 0,
|
|||
MapArea::SubDesert1 | MapArea::SubDesert3 => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::SubDesert2 => 0,
|
|||
MapArea::SaintMillion => 0,
|
|||
};
|
|||
|
|||
let minor = match map {
|
|||
MapArea::Pioneer2Ep1 => 0,
|
|||
MapArea::Forest1 | MapArea::Forest2 => rand::thread_rng().gen_range(0, 5),
|
|||
MapArea::Caves1 | MapArea::Caves2 | MapArea::Caves3 => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Mines1 | MapArea::Mines2 => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Ruins1 | MapArea::Ruins2 | MapArea::Ruins3 => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Dragon | MapArea::DeRolLe | MapArea::VolOpt | MapArea::DarkFalz => 0,
|
|||
|
|||
MapArea::Pioneer2Ep2 => 0,
|
|||
MapArea::VrTempleAlpha | MapArea::VrTempleBeta => 0,
|
|||
MapArea::VrSpaceshipAlpha | MapArea::VrSpaceshipBeta => 0,
|
|||
MapArea::Cca => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::JungleAreaNorth | MapArea::JungleAreaEast => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::Mountain => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Seaside | MapArea::SeasideNight => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::SeabedUpper | MapArea::SeabedLower => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::BarbaRay | MapArea::GolDragon | MapArea::GalGryphon | MapArea::OlgaFlow => 0,
|
|||
MapArea::Tower => 0,
|
|||
|
|||
MapArea::Pioneer2Ep4 => 0,
|
|||
MapArea::CraterEast | MapArea::CraterWest | MapArea::CraterSouth | MapArea::CraterNorth | MapArea::CraterInterior => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::SubDesert1 | MapArea::SubDesert3 => 0,
|
|||
MapArea::SubDesert2 => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::SaintMillion => 0,
|
|||
};
|
|||
|
|||
MapVariant {
|
|||
map: map,
|
|||
mode: mode,
|
|||
major: major,
|
|||
minor: minor,
|
|||
}
|
|||
}
|
|||
else {
|
|||
let major = match map {
|
|||
MapArea::Pioneer2Ep1 => 0,
|
|||
MapArea::Forest1 | MapArea::Forest2 => 0,
|
|||
MapArea::Caves1 | MapArea::Caves2 | MapArea::Caves3 => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::Mines1 | MapArea::Mines2 => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::Ruins1 | MapArea::Ruins2 | MapArea::Ruins3 => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::Dragon | MapArea::DeRolLe | MapArea::VolOpt | MapArea::DarkFalz => 0,
|
|||
|
|||
MapArea::Pioneer2Ep2 => 0,
|
|||
MapArea::VrTempleAlpha | MapArea::VrTempleBeta => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::VrSpaceshipAlpha | MapArea::VrSpaceshipBeta => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Cca => 0,
|
|||
MapArea::JungleAreaNorth | MapArea::JungleAreaEast => 0,
|
|||
MapArea::Mountain => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Seaside | MapArea::SeasideNight => 0,
|
|||
MapArea::SeabedUpper | MapArea::SeabedLower => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::BarbaRay | MapArea::GolDragon | MapArea::GalGryphon | MapArea::OlgaFlow => 0,
|
|||
MapArea::Tower => 0,
|
|||
|
|||
MapArea::Pioneer2Ep4 => 0,
|
|||
MapArea::CraterEast | MapArea::CraterWest | MapArea::CraterSouth | MapArea::CraterNorth | MapArea::CraterInterior => 0,
|
|||
MapArea::SubDesert1 | MapArea::SubDesert3 => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::SubDesert2 => 0,
|
|||
MapArea::SaintMillion => 0,
|
|||
};
|
|||
|
|||
let minor = match map {
|
|||
MapArea::Pioneer2Ep1 => 0,
|
|||
MapArea::Forest1 | MapArea::Forest2 => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::Caves1 | MapArea::Caves2 | MapArea::Caves3 => 0,
|
|||
MapArea::Mines1 | MapArea::Mines2 => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Ruins1 | MapArea::Ruins2 | MapArea::Ruins3 => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Dragon | MapArea::DeRolLe | MapArea::VolOpt | MapArea::DarkFalz => 0,
|
|||
|
|||
MapArea::Pioneer2Ep2 => 0,
|
|||
MapArea::VrTempleAlpha | MapArea::VrTempleBeta => 0,
|
|||
MapArea::VrSpaceshipAlpha | MapArea::VrSpaceshipBeta => 0,
|
|||
MapArea::Cca => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::JungleAreaNorth | MapArea::JungleAreaEast => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::Mountain => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::Seaside | MapArea::SeasideNight => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::SeabedUpper | MapArea::SeabedLower => 0,
|
|||
MapArea::BarbaRay | MapArea::GolDragon | MapArea::GalGryphon | MapArea::OlgaFlow => 0,
|
|||
MapArea::Tower => 0,
|
|||
|
|||
MapArea::Pioneer2Ep4 => 0,
|
|||
MapArea::CraterEast | MapArea::CraterWest | MapArea::CraterSouth | MapArea::CraterNorth | MapArea::CraterInterior => rand::thread_rng().gen_range(0, 3),
|
|||
MapArea::SubDesert1 | MapArea::SubDesert3 => 0,
|
|||
MapArea::SubDesert2 => rand::thread_rng().gen_range(0, 2),
|
|||
MapArea::SaintMillion => 0,
|
|||
|
|||
};
|
|||
|
|||
MapVariant {
|
|||
map: map,
|
|||
mode: mode,
|
|||
major: major,
|
|||
minor: minor,
|
|||
}
|
|||
}
|
|||
}
|
|||
// TODO: rename to npc_file
|
|||
pub fn dat_file(&self) -> String {
|
|||
if self.mode == MapVariantMode::Online {
|
|||
match self.map {
|
|||
MapArea::Pioneer2Ep1 => "data/maps/map_city00_00e.dat".into(),
|
|||
MapArea::Forest1 => format!("data/maps/map_forest01_0{}e.dat", self.minor),
|
|||
MapArea::Forest2 => format!("data/maps/map_forest02_0{}e.dat", self.minor),
|
|||
MapArea::Caves1 => format!("data/maps/map_cave01_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Caves2 => format!("data/maps/map_cave02_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Caves3 => format!("data/maps/map_cave03_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Mines1 => format!("data/maps/map_machine01_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Mines2 => format!("data/maps/map_machine02_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Ruins1 => format!("data/maps/map_ancient01_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Ruins2 => format!("data/maps/map_ancient02_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Ruins3 => format!("data/maps/map_ancient03_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Dragon => "data/maps/map_boss01e.dat".into(),
|
|||
MapArea::DeRolLe => "data/maps/map_boss02e.dat".into(),
|
|||
MapArea::VolOpt => "data/maps/map_boss03e.dat".into(),
|
|||
MapArea::DarkFalz => "data/maps/map_boss04e.dat".into(),
|
|||
|
|||
MapArea::Pioneer2Ep2 => "data/maps/map_labo00_00e.dat".into(),
|
|||
MapArea::VrTempleAlpha => format!("data/maps/map_ruins01_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::VrTempleBeta => format!("data/maps/map_ruins02_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::VrSpaceshipAlpha => format!("data/maps/map_space01_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::VrSpaceshipBeta => format!("data/maps/map_space02_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Cca => format!("data/maps/map_jungle01_0{}e.dat", self.minor),
|
|||
MapArea::JungleAreaNorth => format!("data/maps/map_jungle02_0{}e.dat", self.minor),
|
|||
MapArea::JungleAreaEast => format!("data/maps/map_jungle03_0{}e.dat", self.minor),
|
|||
MapArea::Mountain => format!("data/maps/map_jungle04_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Seaside => format!("data/maps/map_jungle05_0{}e.dat", self.minor),
|
|||
MapArea::SeabedUpper => format!("data/maps/map_seabed01_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::SeabedLower => format!("data/maps/map_seabed02_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::GalGryphon => "data/maps/map_boss05e.dat".into(),
|
|||
MapArea::OlgaFlow => "data/maps/map_boss06e.dat".into(),
|
|||
MapArea::BarbaRay => "data/maps/map_boss07e.dat".into(),
|
|||
MapArea::GolDragon => "data/maps/map_boss08e.dat".into(),
|
|||
|
|||
MapArea::Pioneer2Ep4 => "data/maps/map_city02_00_00e.dat".into(),
|
|||
MapArea::CraterEast => format!("data/maps/map_wilds01_00_0{}e.dat", self.minor),
|
|||
MapArea::CraterWest => format!("data/maps/map_wilds01_01_0{}e.dat", self.minor),
|
|||
MapArea::CraterSouth => format!("data/maps/map_wilds01_02_0{}e.dat", self.minor),
|
|||
MapArea::CraterNorth => format!("data/maps/map_wilds01_03_0{}e.dat", self.minor),
|
|||
MapArea::CraterInterior => format!("data/maps/map_crater01_00_0{}e.dat", self.minor),
|
|||
MapArea::SubDesert1 => format!("data/maps/map_desert01_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::SubDesert2 => format!("data/maps/map_desert02_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::SubDesert3 => format!("data/maps/map_desert03_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::SaintMillion => "data/maps/map_boss09_00_00e.dat".into(),
|
|||
_ => unreachable!(),
|
|||
}
|
|||
} else { // Offline
|
|||
match self.map {
|
|||
MapArea::Pioneer2Ep1 => "data/maps/map_city00_00e_s.dat".into(),
|
|||
MapArea::Forest1 => format!("data/maps/map_forest01_0{}_offe.dat", self.minor*2),
|
|||
MapArea::Forest2 => {
|
|||
match self.minor {
|
|||
0 => format!("data/maps/map_forest02_00_offe.dat"),
|
|||
1 => format!("data/maps/map_forest02_03_offe.dat"),
|
|||
2 => format!("data/maps/map_forest02_04_offe.dat"),
|
|||
_ => unreachable!()
|
|||
}},
|
|||
MapArea::Caves1 => format!("data/maps/map_cave01_0{}_0{}_offe.dat", self.major, self.minor),
|
|||
MapArea::Caves2 => format!("data/maps/map_cave02_0{}_0{}_offe.dat", self.major, self.minor),
|
|||
MapArea::Caves3 => format!("data/maps/map_cave03_0{}_0{}_offe.dat", self.major, self.minor),
|
|||
MapArea::Mines1 => format!("data/maps/map_machine01_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Mines2 => format!("data/maps/map_machine02_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Ruins1 => format!("data/maps/map_ancient01_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Ruins2 => format!("data/maps/map_ancient02_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Ruins3 => format!("data/maps/map_ancient03_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::Dragon => "data/maps/map_boss01e.dat".into(),
|
|||
MapArea::DeRolLe => "data/maps/map_boss02e.dat".into(),
|
|||
MapArea::VolOpt => "data/maps/map_boss03e.dat".into(),
|
|||
MapArea::DarkFalz => "data/maps/map_boss04e.dat".into(),
|
|||
|
|||
MapArea::Pioneer2Ep2 => "data/maps/map_labo00_00e_s.dat".into(),
|
|||
MapArea::VrTempleAlpha => format!("data/maps/map_ruins01_0{}_0{}_offe.dat", self.major, self.minor),
|
|||
MapArea::VrTempleBeta => format!("data/maps/map_ruins02_0{}_0{}_offe.dat", self.major, self.minor),
|
|||
MapArea::VrSpaceshipAlpha => format!("data/maps/map_space01_0{}_0{}_offe.dat", self.major, self.minor),
|
|||
MapArea::VrSpaceshipBeta => format!("data/maps/map_space02_0{}_0{}_offe.dat", self.major, self.minor),
|
|||
MapArea::Cca => format!("data/maps/map_jungle01_0{}_offe.dat", self.minor),
|
|||
MapArea::JungleAreaNorth => format!("data/maps/map_jungle02_0{}_offe.dat", self.minor),
|
|||
MapArea::JungleAreaEast => format!("data/maps/map_jungle03_0{}_offe.dat", self.minor),
|
|||
MapArea::Mountain => format!("data/maps/map_jungle04_0{}_0{}_offe.dat", self.major, self.minor),
|
|||
MapArea::Seaside => format!("data/maps/map_jungle05_0{}_offe.dat", self.minor),
|
|||
MapArea::SeabedUpper => format!("data/maps/map_seabed01_0{}_0{}_offe.dat", self.major, self.minor),
|
|||
MapArea::SeabedLower => format!("data/maps/map_seabed02_0{}_0{}_offe.dat", self.major, self.minor),
|
|||
MapArea::GalGryphon => "data/maps/map_boss05e.dat".into(),
|
|||
MapArea::OlgaFlow => "data/maps/map_boss06e.dat".into(),
|
|||
MapArea::BarbaRay => "data/maps/map_boss07e.dat".into(),
|
|||
MapArea::GolDragon => "data/maps/map_boss08e.dat".into(),
|
|||
|
|||
MapArea::Pioneer2Ep4 => "data/maps/map_city02_00_00e_s.dat".into(),
|
|||
MapArea::CraterEast => format!("data/maps/map_wilds01_00_0{}e.dat", self.minor),
|
|||
MapArea::CraterWest => format!("data/maps/map_wilds01_01_0{}e.dat", self.minor),
|
|||
MapArea::CraterSouth => format!("data/maps/map_wilds01_02_0{}e.dat", self.minor),
|
|||
MapArea::CraterNorth => format!("data/maps/map_wilds01_03_0{}e.dat", self.minor),
|
|||
MapArea::CraterInterior => format!("data/maps/map_crater01_00_0{}e.dat", self.minor),
|
|||
MapArea::SubDesert1 => format!("data/maps/map_desert01_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::SubDesert2 => format!("data/maps/map_desert02_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::SubDesert3 => format!("data/maps/map_desert03_0{}_0{}e.dat", self.major, self.minor),
|
|||
MapArea::SaintMillion => "data/maps/map_boss09_00_00e.dat".into(),
|
|||
_ => unreachable!(),
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
pub fn obj_file(&self) -> String {
|
|||
if self.mode == MapVariantMode::Online {
|
|||
match self.map {
|
|||
MapArea::Pioneer2Ep1 => "data/maps/map_city00_00o.dat".into(),
|
|||
MapArea::Forest1 => format!("data/maps/map_forest01_0{}o.dat", self.minor),
|
|||
MapArea::Forest2 => format!("data/maps/map_forest02_0{}o.dat", self.minor),
|
|||
MapArea::Caves1 => format!("data/maps/map_cave01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Caves2 => format!("data/maps/map_cave02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Caves3 => format!("data/maps/map_cave03_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Mines1 => format!("data/maps/map_machine01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Mines2 => format!("data/maps/map_machine02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Ruins1 => format!("data/maps/map_ancient01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Ruins2 => format!("data/maps/map_ancient02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Ruins3 => format!("data/maps/map_ancient03_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Dragon => "data/maps/map_boss01o.dat".into(),
|
|||
MapArea::DeRolLe => "data/maps/map_boss02o.dat".into(),
|
|||
MapArea::VolOpt => "data/maps/map_boss03o.dat".into(),
|
|||
MapArea::DarkFalz => "data/maps/map_boss04o.dat".into(),
|
|||
|
|||
MapArea::Pioneer2Ep2 => "data/maps/map_labo00_00o.dat".into(),
|
|||
MapArea::VrTempleAlpha => format!("data/maps/map_ruins01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::VrTempleBeta => format!("data/maps/map_ruins02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::VrSpaceshipAlpha => format!("data/maps/map_space01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::VrSpaceshipBeta => format!("data/maps/map_space02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Cca => format!("data/maps/map_jungle01_0{}o.dat", self.minor),
|
|||
MapArea::JungleAreaNorth => format!("data/maps/map_jungle02_0{}o.dat", self.minor),
|
|||
MapArea::JungleAreaEast => format!("data/maps/map_jungle03_0{}o.dat", self.minor),
|
|||
MapArea::Mountain => format!("data/maps/map_jungle04_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Seaside => format!("data/maps/map_jungle05_0{}o.dat", self.minor),
|
|||
MapArea::SeabedUpper => format!("data/maps/map_seabed01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::SeabedLower => format!("data/maps/map_seabed02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::GalGryphon => "data/maps/map_boss05o.dat".into(),
|
|||
MapArea::OlgaFlow => "data/maps/map_boss06o.dat".into(),
|
|||
MapArea::BarbaRay => "data/maps/map_boss07o.dat".into(),
|
|||
MapArea::GolDragon => "data/maps/map_boss08o.dat".into(),
|
|||
|
|||
MapArea::Pioneer2Ep4 => "data/maps/map_city02_00_00o.dat".into(),
|
|||
MapArea::CraterEast => format!("data/maps/map_wilds01_00_0{}o.dat", self.minor),
|
|||
MapArea::CraterWest => format!("data/maps/map_wilds01_01_0{}o.dat", self.minor),
|
|||
MapArea::CraterSouth => format!("data/maps/map_wilds01_02_0{}o.dat", self.minor),
|
|||
MapArea::CraterNorth => format!("data/maps/map_wilds01_03_0{}o.dat", self.minor),
|
|||
MapArea::CraterInterior => format!("data/maps/map_crater01_00_0{}o.dat", self.minor),
|
|||
MapArea::SubDesert1 => format!("data/maps/map_desert01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::SubDesert2 => format!("data/maps/map_desert02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::SubDesert3 => format!("data/maps/map_desert03_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::SaintMillion => "data/maps/map_boss09_00_00o.dat".into(),
|
|||
_ => unreachable!(),
|
|||
}
|
|||
} else {
|
|||
match self.map {
|
|||
MapArea::Pioneer2Ep1 => "data/maps/map_city00_00o_s.dat".into(),
|
|||
MapArea::Forest1 => format!("data/maps/map_forest01_0{}o.dat", self.minor*2),
|
|||
MapArea::Forest2 => {
|
|||
match self.minor {
|
|||
0 => format!("data/maps/map_forest02_00o.dat"),
|
|||
1 => format!("data/maps/map_forest02_03o.dat"),
|
|||
2 => format!("data/maps/map_forest02_04o.dat"),
|
|||
_ => unreachable!()
|
|||
}},
|
|||
MapArea::Caves1 => format!("data/maps/map_cave01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Caves2 => format!("data/maps/map_cave02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Caves3 => format!("data/maps/map_cave03_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Mines1 => format!("data/maps/map_machine01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Mines2 => format!("data/maps/map_machine02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Ruins1 => format!("data/maps/map_ancient01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Ruins2 => format!("data/maps/map_ancient02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Ruins3 => format!("data/maps/map_ancient03_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::Dragon => "data/maps/map_boss01o.dat".into(),
|
|||
MapArea::DeRolLe => "data/maps/map_boss02o.dat".into(),
|
|||
MapArea::VolOpt => "data/maps/map_boss03o.dat".into(),
|
|||
MapArea::DarkFalz => "data/maps/map_boss04_offo.dat".into(),
|
|||
|
|||
MapArea::Pioneer2Ep2 => "data/maps/map_labo00_00o_s.dat".into(),
|
|||
MapArea::VrTempleAlpha => format!("data/maps/map_ruins01_0{}_0{}_offo.dat", self.major, self.minor),
|
|||
MapArea::VrTempleBeta => format!("data/maps/map_ruins02_0{}_0{}_offo.dat", self.major, self.minor),
|
|||
MapArea::VrSpaceshipAlpha => format!("data/maps/map_space01_0{}_0{}_offo.dat", self.major, self.minor),
|
|||
MapArea::VrSpaceshipBeta => format!("data/maps/map_space02_0{}_0{}_offo.dat", self.major, self.minor),
|
|||
MapArea::Cca => format!("data/maps/map_jungle01_0{}_offo.dat", self.minor),
|
|||
MapArea::JungleAreaNorth => format!("data/maps/map_jungle02_0{}_offo.dat", self.minor),
|
|||
MapArea::JungleAreaEast => format!("data/maps/map_jungle03_0{}_offo.dat", self.minor),
|
|||
MapArea::Mountain => format!("data/maps/map_jungle04_0{}_0{}_offo.dat", self.major, self.minor),
|
|||
MapArea::Seaside => format!("data/maps/map_jungle05_0{}_offo.dat", self.minor),
|
|||
MapArea::SeabedUpper => format!("data/maps/map_seabed01_0{}_0{}_offo.dat", self.major, self.minor),
|
|||
MapArea::SeabedLower => format!("data/maps/map_seabed02_0{}_0{}_offo.dat", self.major, self.minor),
|
|||
MapArea::GalGryphon => "data/maps/map_boss05_offo.dat".into(),
|
|||
MapArea::OlgaFlow => "data/maps/map_boss06_offo.dat".into(),
|
|||
MapArea::BarbaRay => "data/maps/map_boss07_offo.dat".into(),
|
|||
MapArea::GolDragon => "data/maps/map_boss08_offo.dat".into(),
|
|||
|
|||
MapArea::Pioneer2Ep4 => "data/maps/map_city02_00_00o_s.dat".into(),
|
|||
MapArea::CraterEast => format!("data/maps/map_wilds01_00_0{}o.dat", self.minor),
|
|||
MapArea::CraterWest => format!("data/maps/map_wilds01_01_0{}o.dat", self.minor),
|
|||
MapArea::CraterSouth => format!("data/maps/map_wilds01_02_0{}o.dat", self.minor),
|
|||
MapArea::CraterNorth => format!("data/maps/map_wilds01_03_0{}o.dat", self.minor),
|
|||
MapArea::CraterInterior => format!("data/maps/map_crater01_00_0{}o.dat", self.minor),
|
|||
MapArea::SubDesert1 => format!("data/maps/map_desert01_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::SubDesert2 => format!("data/maps/map_desert02_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::SubDesert3 => format!("data/maps/map_desert03_0{}_0{}o.dat", self.major, self.minor),
|
|||
MapArea::SaintMillion => "data/maps/map_boss09_00_00o.dat".into(),
|
|||
_ => unreachable!(),
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
pub fn pkt_header(&self) -> [u8; 2] {
|
|||
[self.major, self.minor]
|
|||
}
|
|||
}
|
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue