You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

362 lines
17 KiB

  1. // TOOD: `pub(super) for most of these?`
  2. use std::path::PathBuf;
  3. use std::io::{Read};
  4. use std::fs::File;
  5. use thiserror::Error;
  6. use crate::ship::monster::MonsterType;
  7. use crate::ship::room::{Episode, RoomMode};
  8. // TODO: don't use *
  9. use crate::ship::map::*;
  10. pub fn objects_from_stream(cursor: &mut impl Read, episode: &Episode, map_area: &MapArea) -> Vec<Option<MapObject>> {
  11. let mut object_data = Vec::new();
  12. while let Ok(raw_object) = RawMapObject::from_byte_stream(cursor) {
  13. let object = MapObject::from_raw(raw_object, *episode, map_area);
  14. object_data.push(object.ok());
  15. }
  16. object_data
  17. }
  18. fn objects_from_map_data(path: PathBuf, episode: &Episode, map_area: &MapArea) -> Vec<Option<MapObject>> {
  19. let mut cursor = File::open(path).unwrap();
  20. objects_from_stream(&mut cursor, episode, map_area)
  21. }
  22. fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) -> Vec<Option<MapEnemy>> {
  23. let enemy = MapEnemy::from_raw(raw_enemy, episode, map_area);
  24. enemy
  25. .map_or(vec![None], |monster| {
  26. let mut monsters = vec![Some(monster)];
  27. match monster.monster {
  28. MonsterType::Monest => {
  29. for _ in 0..30 {
  30. monsters.push(Some(MapEnemy::new(MonsterType::Mothmant, monster.map_area)));
  31. }
  32. },
  33. MonsterType::PanArms => {
  34. monsters.push(Some(MapEnemy::new(MonsterType::Hidoom, monster.map_area)));
  35. monsters.push(Some(MapEnemy::new(MonsterType::Migium, monster.map_area)));
  36. },
  37. MonsterType::PofuillySlime => {
  38. for _ in 0..5 {
  39. monsters.push(Some(MapEnemy::new(MonsterType::PofuillySlime, monster.map_area)));
  40. }
  41. },
  42. MonsterType::PouillySlime => {
  43. for _ in 0..5 {
  44. monsters.push(Some(MapEnemy::new(MonsterType::PofuillySlime, monster.map_area)));
  45. }
  46. },
  47. MonsterType::SinowBeat => {
  48. for _ in 0..4 {
  49. monsters.push(Some(MapEnemy::new(MonsterType::SinowBeat, monster.map_area)));
  50. }
  51. },
  52. MonsterType::SinowGold => {
  53. for _ in 0..4 {
  54. monsters.push(Some(MapEnemy::new(MonsterType::SinowGold, monster.map_area)));
  55. }
  56. },
  57. MonsterType::Canane => {
  58. for _ in 0..8 {
  59. monsters.push(Some(MapEnemy::new(MonsterType::RingCanadine, monster.map_area)));
  60. }
  61. },
  62. MonsterType::ChaosSorcerer => {
  63. monsters.push(Some(MapEnemy::new(MonsterType::BeeR, monster.map_area)));
  64. monsters.push(Some(MapEnemy::new(MonsterType::BeeL, monster.map_area)));
  65. },
  66. MonsterType::Bulclaw => {
  67. for _ in 0..4 {
  68. monsters.push(Some(MapEnemy::new(MonsterType::Claw, monster.map_area)));
  69. }
  70. },
  71. MonsterType::DeRolLe => {
  72. for _ in 0..10 {
  73. monsters.push(Some(MapEnemy::new(MonsterType::DeRolLeBody, monster.map_area)));
  74. }
  75. for _ in 0..9 {
  76. monsters.push(Some(MapEnemy::new(MonsterType::DeRolLeMine, monster.map_area)));
  77. }
  78. },
  79. MonsterType::VolOptPartA => {
  80. for _ in 0..6 {
  81. monsters.push(Some(MapEnemy::new(MonsterType::VolOptPillar, monster.map_area)));
  82. }
  83. for _ in 0..24 {
  84. monsters.push(Some(MapEnemy::new(MonsterType::VolOptMonitor, monster.map_area)));
  85. }
  86. for _ in 0..2 {
  87. monsters.push(Some(MapEnemy::new(MonsterType::VolOptUnused, monster.map_area)));
  88. }
  89. monsters.push(Some(MapEnemy::new(MonsterType::VolOptAmp, monster.map_area)));
  90. monsters.push(Some(MapEnemy::new(MonsterType::VolOptCore, monster.map_area)));
  91. monsters.push(Some(MapEnemy::new(MonsterType::VolOptUnused, monster.map_area)));
  92. },
  93. // TOOD: this cares about difficulty (theres an ult-specific darvant?)
  94. MonsterType::DarkFalz => {
  95. for _ in 0..509 {
  96. monsters.push(Some(MapEnemy::new(MonsterType::Darvant, monster.map_area)));
  97. }
  98. monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz3, monster.map_area)));
  99. monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz2, monster.map_area)));
  100. monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz1, monster.map_area)));
  101. },
  102. MonsterType::OlgaFlow => {
  103. for _ in 0..512 {
  104. monsters.push(Some(MapEnemy::new(MonsterType::OlgaFlow, monster.map_area)));
  105. }
  106. },
  107. MonsterType::BarbaRay => {
  108. for _ in 0..47 {
  109. monsters.push(Some(MapEnemy::new(MonsterType::PigRay, monster.map_area)));
  110. }
  111. },
  112. MonsterType::GolDragon => {
  113. for _ in 0..5 {
  114. monsters.push(Some(MapEnemy::new(MonsterType::GolDragon, monster.map_area)));
  115. }
  116. },
  117. MonsterType::SinowBerill => {
  118. for _ in 0..4 {
  119. monsters.push(Some(MapEnemy::new(MonsterType::SinowBerill, monster.map_area))); // unused clones
  120. }
  121. },
  122. MonsterType::SinowSpigell => {
  123. for _ in 0..4 {
  124. monsters.push(Some(MapEnemy::new(MonsterType::SinowSpigell, monster.map_area))); // unused clones
  125. }
  126. },
  127. MonsterType::Recobox => { // + recons
  128. for _ in 0..raw_enemy.children {
  129. monsters.push(Some(MapEnemy::new(MonsterType::Recon, monster.map_area)));
  130. }
  131. },
  132. MonsterType::Epsilon => {
  133. for _ in 0..4 {
  134. monsters.push(Some(MapEnemy::new(MonsterType::Epsiguard, monster.map_area)));
  135. }
  136. },
  137. _ => {
  138. for _ in 0..raw_enemy.children {
  139. monsters.push(Some(MapEnemy::new(monster.monster, monster.map_area)));
  140. }
  141. }
  142. }
  143. monsters
  144. })
  145. }
  146. pub fn enemy_data_from_stream(cursor: &mut impl Read, map_area: &MapArea, episode: &Episode) -> Vec<Option<MapEnemy>> {
  147. let mut enemy_data = Vec::new();
  148. while let Ok(enemy) = RawMapEnemy::from_byte_stream(cursor) {
  149. enemy_data.append(&mut parse_enemy(episode, map_area, enemy));
  150. }
  151. enemy_data
  152. }
  153. fn enemy_data_from_map_data(map_variant: &MapVariant, episode: &Episode) -> Vec<Option<MapEnemy>> {
  154. let path = map_variant.dat_file();
  155. let mut cursor = File::open(path).unwrap();
  156. enemy_data_from_stream(&mut cursor, &map_variant.map, episode)
  157. }
  158. #[derive(Error, Debug)]
  159. #[error("")]
  160. pub enum MapsError {
  161. InvalidMonsterId(usize),
  162. InvalidObjectId(usize),
  163. }
  164. #[derive(Debug)]
  165. pub struct Maps {
  166. map_variants: Vec<MapVariant>,
  167. enemy_data: Vec<Option<MapEnemy>>,
  168. object_data: Vec<Option<MapObject>>,
  169. }
  170. impl Maps {
  171. pub fn new(room_mode: RoomMode, rare_monster_table: &enemy::RareMonsterAppearTable) -> Maps {
  172. let map_variants = match (room_mode.episode(), room_mode.single_player()) {
  173. (Episode::One, 0) => {
  174. vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Online),
  175. MapVariant::new(MapArea::Forest1, MapVariantMode::Online),
  176. MapVariant::new(MapArea::Forest2, MapVariantMode::Online),
  177. MapVariant::new(MapArea::Caves1, MapVariantMode::Online),
  178. MapVariant::new(MapArea::Caves2, MapVariantMode::Online),
  179. MapVariant::new(MapArea::Caves3, MapVariantMode::Online),
  180. MapVariant::new(MapArea::Mines1, MapVariantMode::Online),
  181. MapVariant::new(MapArea::Mines2, MapVariantMode::Online),
  182. MapVariant::new(MapArea::Ruins1, MapVariantMode::Online),
  183. MapVariant::new(MapArea::Ruins2, MapVariantMode::Online),
  184. MapVariant::new(MapArea::Ruins3, MapVariantMode::Online),
  185. MapVariant::new(MapArea::Dragon, MapVariantMode::Online),
  186. MapVariant::new(MapArea::DeRolLe, MapVariantMode::Online),
  187. MapVariant::new(MapArea::VolOpt, MapVariantMode::Online),
  188. MapVariant::new(MapArea::DarkFalz, MapVariantMode::Online),
  189. ]
  190. },
  191. (Episode::One, 1) => {
  192. vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Offline),
  193. MapVariant::new(MapArea::Forest1, MapVariantMode::Offline),
  194. MapVariant::new(MapArea::Forest2, MapVariantMode::Offline),
  195. MapVariant::new(MapArea::Caves1, MapVariantMode::Offline),
  196. MapVariant::new(MapArea::Caves2, MapVariantMode::Offline),
  197. MapVariant::new(MapArea::Caves3, MapVariantMode::Offline),
  198. MapVariant::new(MapArea::Mines1, MapVariantMode::Offline),
  199. MapVariant::new(MapArea::Mines2, MapVariantMode::Offline),
  200. MapVariant::new(MapArea::Ruins1, MapVariantMode::Offline),
  201. MapVariant::new(MapArea::Ruins2, MapVariantMode::Offline),
  202. MapVariant::new(MapArea::Ruins3, MapVariantMode::Offline),
  203. MapVariant::new(MapArea::Dragon, MapVariantMode::Offline),
  204. MapVariant::new(MapArea::DeRolLe, MapVariantMode::Offline),
  205. MapVariant::new(MapArea::VolOpt, MapVariantMode::Offline),
  206. MapVariant::new(MapArea::DarkFalz, MapVariantMode::Offline),
  207. ]
  208. },
  209. (Episode::Two, 0) => {
  210. vec![MapVariant::new(MapArea::Pioneer2Ep2, MapVariantMode::Online),
  211. MapVariant::new(MapArea::VrTempleAlpha, MapVariantMode::Online),
  212. MapVariant::new(MapArea::VrTempleBeta, MapVariantMode::Online),
  213. MapVariant::new(MapArea::VrSpaceshipAlpha, MapVariantMode::Online),
  214. MapVariant::new(MapArea::VrSpaceshipBeta, MapVariantMode::Online),
  215. MapVariant::new(MapArea::Cca, MapVariantMode::Online),
  216. MapVariant::new(MapArea::JungleAreaNorth, MapVariantMode::Online),
  217. MapVariant::new(MapArea::JungleAreaEast, MapVariantMode::Online),
  218. MapVariant::new(MapArea::Mountain, MapVariantMode::Online),
  219. MapVariant::new(MapArea::Seaside, MapVariantMode::Online),
  220. MapVariant::new(MapArea::SeabedUpper, MapVariantMode::Online),
  221. MapVariant::new(MapArea::SeabedLower, MapVariantMode::Online),
  222. MapVariant::new(MapArea::GalGryphon, MapVariantMode::Online),
  223. MapVariant::new(MapArea::OlgaFlow, MapVariantMode::Online),
  224. MapVariant::new(MapArea::BarbaRay, MapVariantMode::Online),
  225. MapVariant::new(MapArea::GolDragon, MapVariantMode::Online),
  226. ]
  227. },
  228. (Episode::Two, 1) => {
  229. vec![MapVariant::new(MapArea::Pioneer2Ep2, MapVariantMode::Offline),
  230. MapVariant::new(MapArea::VrTempleAlpha, MapVariantMode::Offline),
  231. MapVariant::new(MapArea::VrTempleBeta, MapVariantMode::Offline),
  232. MapVariant::new(MapArea::VrSpaceshipAlpha, MapVariantMode::Offline),
  233. MapVariant::new(MapArea::VrSpaceshipBeta, MapVariantMode::Offline),
  234. MapVariant::new(MapArea::Cca, MapVariantMode::Offline),
  235. MapVariant::new(MapArea::JungleAreaNorth, MapVariantMode::Offline),
  236. MapVariant::new(MapArea::JungleAreaEast, MapVariantMode::Offline),
  237. MapVariant::new(MapArea::Mountain, MapVariantMode::Offline),
  238. MapVariant::new(MapArea::Seaside, MapVariantMode::Offline),
  239. MapVariant::new(MapArea::SeabedUpper, MapVariantMode::Offline),
  240. MapVariant::new(MapArea::SeabedLower, MapVariantMode::Offline),
  241. MapVariant::new(MapArea::GalGryphon, MapVariantMode::Offline),
  242. MapVariant::new(MapArea::OlgaFlow, MapVariantMode::Offline),
  243. MapVariant::new(MapArea::BarbaRay, MapVariantMode::Offline),
  244. MapVariant::new(MapArea::GolDragon, MapVariantMode::Offline),
  245. ]
  246. },
  247. (Episode::Four, _) => {
  248. vec![MapVariant::new(MapArea::Pioneer2Ep4, MapVariantMode::Online),
  249. MapVariant::new(MapArea::CraterEast, MapVariantMode::Online),
  250. MapVariant::new(MapArea::CraterWest, MapVariantMode::Online),
  251. MapVariant::new(MapArea::CraterSouth, MapVariantMode::Online),
  252. MapVariant::new(MapArea::CraterNorth, MapVariantMode::Online),
  253. MapVariant::new(MapArea::CraterInterior, MapVariantMode::Online),
  254. MapVariant::new(MapArea::SubDesert1, MapVariantMode::Online),
  255. MapVariant::new(MapArea::SubDesert2, MapVariantMode::Online),
  256. MapVariant::new(MapArea::SubDesert3, MapVariantMode::Online),
  257. MapVariant::new(MapArea::SaintMillion, MapVariantMode::Online),
  258. ]
  259. },
  260. _ => unreachable!()
  261. };
  262. let mut maps = Maps {
  263. enemy_data: map_variants.iter()
  264. .fold(Vec::new(), |mut enemy_data, map_variant| {
  265. enemy_data.append(&mut enemy_data_from_map_data(map_variant, &room_mode.episode()));
  266. enemy_data
  267. }),
  268. object_data: map_variants.iter()
  269. .flat_map(|map_variant| {
  270. objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map)
  271. }).collect(),
  272. map_variants,
  273. };
  274. maps.roll_monster_appearance(rare_monster_table);
  275. maps
  276. }
  277. pub fn enemy_by_id(&self, id: usize) -> Result<MapEnemy, MapsError> {
  278. self.enemy_data[id].ok_or(MapsError::InvalidMonsterId(id))
  279. }
  280. pub fn object_by_id(&self, id: usize) -> Result<MapObject, MapsError> {
  281. self.object_data[id].ok_or(MapsError::InvalidObjectId(id))
  282. }
  283. pub fn map_headers(&self) -> [u32; 0x20] {
  284. self.map_variants.iter()
  285. .enumerate()
  286. .fold([0; 0x20], |mut header, (i, map_variant)| {
  287. let [major, minor] = map_variant.pkt_header();
  288. header[i*2] = major as u32;
  289. header[i*2 + 1] = minor as u32;
  290. header
  291. })
  292. }
  293. pub fn set_quest_data(&mut self, enemies: Vec<Option<MapEnemy>>, objects: Vec<Option<MapObject>>, rare_monster_appear_table: &RareMonsterAppearTable) {
  294. self.enemy_data = enemies;
  295. self.roll_monster_appearance(rare_monster_appear_table);
  296. self.object_data = objects;
  297. }
  298. pub fn get_rare_monster_list(&self) -> Vec<u16> {
  299. let mut rare_monsters = vec![0xFFFF; 16];
  300. let shiny: Vec<(usize, &Option<MapEnemy>)> = self.enemy_data.iter()
  301. .enumerate()
  302. .filter(|(_,m)| {
  303. if m.is_some() {
  304. m.unwrap().shiny
  305. } else {
  306. false
  307. }
  308. })
  309. .collect();
  310. for monster in &shiny {
  311. if let Some(j) = rare_monsters.iter().position(|&x| x == 0xFFFF) {
  312. rare_monsters[j] = monster.0 as u16;
  313. } else {
  314. break
  315. }
  316. }
  317. rare_monsters
  318. }
  319. pub fn roll_monster_appearance(&mut self, rare_monster_table: &RareMonsterAppearTable) {
  320. self.enemy_data = self.enemy_data
  321. .iter()
  322. // .map(|&x| if x.is_some() && x.unwrap().has_rare_appearance() {
  323. .map(|&x|
  324. if let Some(monster) = x {
  325. if monster.has_rare_appearance() {
  326. Some(monster.roll_appearance_for_mission(rare_monster_table))
  327. } else {
  328. Some(monster)
  329. }
  330. } else {
  331. x
  332. }
  333. )
  334. .collect();
  335. }
  336. }