// TOOD: `pub(super) for most of these?` use serde::{Serialize, Deserialize}; use std::collections::HashMap; use thiserror::Error; use crate::ship::room::Episode; #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] 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_bb_map_designate(map_number: u8) -> Option { match map_number { 0 => Some(MapArea::Pioneer2Ep1), 1 => Some(MapArea::Forest1), 2 => Some(MapArea::Forest2), 3 => Some(MapArea::Caves1), 4 => Some(MapArea::Caves2), 5 => Some(MapArea::Caves3), 6 => Some(MapArea::Mines1), 7 => Some(MapArea::Mines2), 8 => Some(MapArea::Ruins1), 9 => Some(MapArea::Ruins2), 10 => Some(MapArea::Ruins3), 11 => Some(MapArea::Dragon), 12 => Some(MapArea::DeRolLe), 13 => Some(MapArea::VolOpt), 14 => Some(MapArea::DarkFalz), 18 => Some(MapArea::Pioneer2Ep2), 19 => Some(MapArea::VrTempleAlpha), 20 => Some(MapArea::VrTempleBeta), 21 => Some(MapArea::VrSpaceshipAlpha), 22 => Some(MapArea::VrSpaceshipBeta), 23 => Some(MapArea::Cca), 24 => Some(MapArea::JungleAreaNorth), 25 => Some(MapArea::JungleAreaEast), 26 => Some(MapArea::Mountain), 27 => Some(MapArea::Seaside), 28 => Some(MapArea::SeabedUpper), 29 => Some(MapArea::SeabedLower), 30 => Some(MapArea::GalGryphon), 31 => Some(MapArea::OlgaFlow), 32 => Some(MapArea::BarbaRay), 33 => Some(MapArea::GolDragon), 34 => Some(MapArea::SeasideNight), 35 => Some(MapArea::Tower), 45 => Some(MapArea::Pioneer2Ep4), 36 => Some(MapArea::CraterEast), 37 => Some(MapArea::CraterWest), 38 => Some(MapArea::CraterSouth), 39 => Some(MapArea::CraterNorth), 40 => Some(MapArea::CraterInterior), 41 => Some(MapArea::SubDesert1), 42 => Some(MapArea::SubDesert2), 43 => Some(MapArea::SubDesert3), 44 => Some(MapArea::SaintMillion), _=> None } } pub fn drop_area_value(&self) -> Option { 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), // TODO: this could also be 9? needs research 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, } } pub fn to_episode(self) -> Episode { match self { MapArea::Pioneer2Ep1 => Episode::One, MapArea::Forest1 => Episode::One, MapArea::Forest2 => Episode::One, MapArea::Caves1 => Episode::One, MapArea::Caves2 => Episode::One, MapArea::Caves3 => Episode::One, MapArea::Mines1 => Episode::One, MapArea::Mines2 => Episode::One, MapArea::Ruins1 => Episode::One, MapArea::Ruins2 => Episode::One, MapArea::Ruins3 => Episode::One, MapArea::Dragon => Episode::One, MapArea::DeRolLe => Episode::One, MapArea::VolOpt => Episode::One, MapArea::DarkFalz => Episode::One, MapArea::Pioneer2Ep2 => Episode::Two, MapArea::VrTempleAlpha => Episode::Two, MapArea::VrTempleBeta => Episode::Two, MapArea::VrSpaceshipAlpha => Episode::Two, MapArea::VrSpaceshipBeta => Episode::Two, MapArea::Cca => Episode::Two, MapArea::JungleAreaNorth => Episode::Two, MapArea::JungleAreaEast => Episode::Two, MapArea::Mountain => Episode::Two, MapArea::Seaside => Episode::Two, MapArea::SeabedUpper => Episode::Two, MapArea::SeabedLower => Episode::Two, MapArea::GalGryphon => Episode::Two, MapArea::OlgaFlow => Episode::Two, MapArea::BarbaRay => Episode::Two, MapArea::GolDragon => Episode::Two, MapArea::SeasideNight => Episode::Two, MapArea::Tower => Episode::Two, MapArea::Pioneer2Ep4 => Episode::Four, MapArea::CraterEast => Episode::Four, MapArea::CraterWest => Episode::Four, MapArea::CraterSouth => Episode::Four, MapArea::CraterNorth => Episode::Four, MapArea::CraterInterior => Episode::Four, MapArea::SubDesert1 => Episode::Four, MapArea::SubDesert2 => Episode::Four, MapArea::SubDesert3 => Episode::Four, MapArea::SaintMillion => Episode::Four, } } } #[derive(Debug, Clone)] pub struct MapAreaLookup(HashMap); impl MapAreaLookup { pub fn get_area_map(&self, map_area: u16) -> Result<&MapArea, MapAreaError> { self.0.get(&map_area).ok_or(MapAreaError::UnknownMapArea(map_area)) } fn default_ep1_maps() -> MapAreaLookup { let mut ep1 = HashMap::new(); ep1.insert(0, MapArea::Pioneer2Ep1); ep1.insert(1, MapArea::Forest1); ep1.insert(2, MapArea::Forest2); ep1.insert(3, MapArea::Caves1); ep1.insert(4, MapArea::Caves2); ep1.insert(5, MapArea::Caves3); ep1.insert(6, MapArea::Mines1); ep1.insert(7, MapArea::Mines2); ep1.insert(8, MapArea::Ruins1); ep1.insert(9, MapArea::Ruins2); ep1.insert(10, MapArea::Ruins3); ep1.insert(11, MapArea::Dragon); ep1.insert(12, MapArea::DeRolLe); ep1.insert(13, MapArea::VolOpt); ep1.insert(14, MapArea::DarkFalz); MapAreaLookup(ep1) } fn default_ep2_maps() -> MapAreaLookup { let mut ep2 = HashMap::new(); ep2.insert(0, MapArea::Pioneer2Ep2); ep2.insert(1, MapArea::VrTempleAlpha); ep2.insert(2, MapArea::VrTempleBeta); ep2.insert(3, MapArea::VrSpaceshipAlpha); ep2.insert(4, MapArea::VrSpaceshipBeta); ep2.insert(5, MapArea::Cca); ep2.insert(6, MapArea::JungleAreaNorth); ep2.insert(7, MapArea::JungleAreaEast); ep2.insert(8, MapArea::Mountain); ep2.insert(9, MapArea::Seaside); ep2.insert(10, MapArea::SeabedUpper); ep2.insert(11, MapArea::SeabedLower); ep2.insert(12, MapArea::GalGryphon); ep2.insert(13, MapArea::OlgaFlow); ep2.insert(14, MapArea::BarbaRay); ep2.insert(15, MapArea::GolDragon); ep2.insert(16, MapArea::SeasideNight); ep2.insert(17, MapArea::Tower); MapAreaLookup(ep2) } fn default_ep4_maps() -> MapAreaLookup { let mut ep4 = HashMap::new(); ep4.insert(0, MapArea::Pioneer2Ep4); ep4.insert(1, MapArea::CraterEast); ep4.insert(2, MapArea::CraterWest); ep4.insert(3, MapArea::CraterSouth); ep4.insert(4, MapArea::CraterNorth); ep4.insert(5, MapArea::CraterInterior); ep4.insert(6, MapArea::SubDesert1); ep4.insert(7, MapArea::SubDesert2); ep4.insert(8, MapArea::SubDesert3); ep4.insert(9, MapArea::SaintMillion); MapAreaLookup(ep4) } pub fn new(episode: &Episode) -> MapAreaLookup { match episode { Episode::One => MapAreaLookup::default_ep1_maps(), Episode::Two => MapAreaLookup::default_ep2_maps(), Episode::Four => MapAreaLookup::default_ep4_maps(), } } } #[derive(Default)] pub struct MapAreaLookupBuilder { map_areas: HashMap, } impl MapAreaLookupBuilder { #[must_use] pub fn add(mut self, value: u16, map_area: MapArea) -> MapAreaLookupBuilder { self.map_areas.insert(value, map_area); self } pub fn build(self) -> MapAreaLookup { MapAreaLookup(self.map_areas) } }