|
|
@ -8,12 +8,13 @@ use thiserror::Error; |
|
|
|
|
|
|
|
use crate::ship::ship::ShipEvent;
|
|
|
|
use crate::ship::monster::MonsterType;
|
|
|
|
use crate::ship::room::{Episode, RoomMode};
|
|
|
|
use crate::ship::room::{Episode, RoomMode, PlayerMode};
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
|
|
@ -35,7 +36,7 @@ fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) -> |
|
|
|
enemy
|
|
|
|
.map_or(vec![None], |monster| {
|
|
|
|
let mut monsters = vec![Some(monster)];
|
|
|
|
|
|
|
|
|
|
|
|
match monster.monster {
|
|
|
|
MonsterType::Monest => {
|
|
|
|
for _ in 0..30 {
|
|
|
@ -172,25 +173,10 @@ fn enemy_data_from_map_data(map_variant: &MapVariant, episode: &Episode) -> Vec< |
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[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, rare_monster_table: &enemy::RareMonsterAppearTable, event: ShipEvent) -> Maps {
|
|
|
|
let map_variants = match (room_mode.episode(), room_mode.single_player()) {
|
|
|
|
(Episode::One, 0) => {
|
|
|
|
vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Online),
|
|
|
|
fn map_variants(episode: Episode, player_mode: PlayerMode) -> Vec<MapVariant> {
|
|
|
|
match (episode, player_mode) {
|
|
|
|
(Episode::One, PlayerMode::Multi) => {
|
|
|
|
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),
|
|
|
@ -205,10 +191,10 @@ impl Maps { |
|
|
|
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),
|
|
|
|
]
|
|
|
|
},
|
|
|
|
(Episode::One, PlayerMode::Single) => {
|
|
|
|
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),
|
|
|
@ -223,10 +209,10 @@ impl Maps { |
|
|
|
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),
|
|
|
|
]
|
|
|
|
},
|
|
|
|
(Episode::Two, PlayerMode::Multi) => {
|
|
|
|
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),
|
|
|
@ -242,10 +228,10 @@ impl Maps { |
|
|
|
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),
|
|
|
|
]
|
|
|
|
},
|
|
|
|
(Episode::Two, PlayerMode::Single) => {
|
|
|
|
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),
|
|
|
@ -261,10 +247,10 @@ impl Maps { |
|
|
|
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),
|
|
|
|
]
|
|
|
|
},
|
|
|
|
(Episode::Four, PlayerMode::Multi) => {
|
|
|
|
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),
|
|
|
@ -274,23 +260,44 @@ impl Maps { |
|
|
|
MapVariant::new(MapArea::SubDesert2, MapVariantMode::Online),
|
|
|
|
MapVariant::new(MapArea::SubDesert3, MapVariantMode::Online),
|
|
|
|
MapVariant::new(MapArea::SaintMillion, MapVariantMode::Online),
|
|
|
|
]
|
|
|
|
},
|
|
|
|
_ => unreachable!()
|
|
|
|
};
|
|
|
|
]
|
|
|
|
},
|
|
|
|
(Episode::Four, PlayerMode::Single) => {
|
|
|
|
vec![MapVariant::new(MapArea::Pioneer2Ep4, MapVariantMode::Offline),
|
|
|
|
MapVariant::new(MapArea::CraterEast, MapVariantMode::Offline),
|
|
|
|
MapVariant::new(MapArea::CraterWest, MapVariantMode::Offline),
|
|
|
|
MapVariant::new(MapArea::CraterSouth, MapVariantMode::Offline),
|
|
|
|
MapVariant::new(MapArea::CraterNorth, MapVariantMode::Offline),
|
|
|
|
MapVariant::new(MapArea::CraterInterior, MapVariantMode::Offline),
|
|
|
|
MapVariant::new(MapArea::SubDesert1, MapVariantMode::Offline),
|
|
|
|
MapVariant::new(MapArea::SubDesert2, MapVariantMode::Offline),
|
|
|
|
MapVariant::new(MapArea::SubDesert3, MapVariantMode::Offline),
|
|
|
|
MapVariant::new(MapArea::SaintMillion, MapVariantMode::Offline),
|
|
|
|
]
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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(map_variants: Vec<MapVariant>, enemy_data: Vec<Option<MapEnemy>>, object_data: Vec<Option<MapObject>>) -> Maps {
|
|
|
|
Maps {
|
|
|
|
enemy_data: map_variants.iter()
|
|
|
|
.flat_map(|map_variant| {
|
|
|
|
enemy_data_from_map_data(map_variant, &room_mode.episode())
|
|
|
|
})
|
|
|
|
.map(|enemy| apply_rare_enemy(enemy, rare_monster_table, event))
|
|
|
|
.collect(),
|
|
|
|
object_data: map_variants.iter()
|
|
|
|
.flat_map(|map_variant| {
|
|
|
|
objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map)
|
|
|
|
}).collect(),
|
|
|
|
map_variants,
|
|
|
|
enemy_data,
|
|
|
|
object_data,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
@ -322,7 +329,7 @@ impl Maps { |
|
|
|
{
|
|
|
|
self.enemy_data = enemies
|
|
|
|
.into_iter()
|
|
|
|
.map(|enemy| apply_rare_enemy(enemy, rare_monster_table, event))
|
|
|
|
.map(|enemy| enemy.map(|enemy| rare_monster_table.apply(enemy, event)))
|
|
|
|
.collect();
|
|
|
|
self.object_data = objects;
|
|
|
|
}
|
|
|
@ -351,13 +358,37 @@ impl Maps { |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn apply_rare_enemy(enemy: Option<MapEnemy>, rare_enemy_table: &RareMonsterAppearTable, event: ShipEvent) -> Option<MapEnemy> {
|
|
|
|
enemy.map(|enemy| {
|
|
|
|
if enemy.can_be_rare() && rare_enemy_table.roll_is_rare(&enemy.monster) {
|
|
|
|
enemy.into_rare(event)
|
|
|
|
pub trait MapBuilder: Send + Sync {
|
|
|
|
fn generate_maps(&self, room_mode: RoomMode, event: ShipEvent) -> Maps;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct FreeRoamMapBuilder {
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FreeRoamMapBuilder {
|
|
|
|
pub fn new() -> FreeRoamMapBuilder {
|
|
|
|
FreeRoamMapBuilder {
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
enemy
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MapBuilder for FreeRoamMapBuilder {
|
|
|
|
fn generate_maps(&self, room_mode: RoomMode, event: ShipEvent) -> Maps {
|
|
|
|
let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode());
|
|
|
|
let map_variants = map_variants(room_mode.episode(), room_mode.player_mode());
|
|
|
|
Maps {
|
|
|
|
enemy_data: map_variants.iter()
|
|
|
|
.flat_map(|map_variant| {
|
|
|
|
enemy_data_from_map_data(map_variant, &room_mode.episode())
|
|
|
|
})
|
|
|
|
.map(|enemy| enemy.map(|enemy| rare_monster_table.apply(enemy, event)))
|
|
|
|
.collect(),
|
|
|
|
object_data: map_variants.iter()
|
|
|
|
.flat_map(|map_variant| {
|
|
|
|
objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map)
|
|
|
|
}).collect(),
|
|
|
|
map_variants,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|