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.

378 lines
18 KiB

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