use std::collections::HashMap; use serde::{Serialize, Deserialize}; use crate::entity::item::tool::ToolType; use std::io::Read; #[derive(Debug, Deserialize)] struct MagStats { feed_table: u32, } #[derive(Debug, Deserialize)] struct MagFeedTable { def: i32, pow: i32, dex: i32, mnd: i32, iq: i32, syn: i32, } lazy_static::lazy_static! { static ref MAG_STATS: HashMap = { let mut f = std::fs::File::open("data/item_stats/mag_stats.toml").unwrap(); let mut s = String::new(); f.read_to_string(&mut s).unwrap(); let mag_stats: HashMap = toml::from_str(&s).unwrap(); mag_stats.into_iter() .map(|(name, stats)| { (name.parse().unwrap(), stats) }) .collect::>() }; static ref MAG_FEEDING_TABLES: Vec> = { let mut f = std::fs::File::open("data/item_stats/mag_feed_table.toml").unwrap(); let mut s = String::new(); f.read_to_string(&mut s).unwrap(); let mut feed: HashMap>> = toml::from_str(&s).unwrap(); let feed = feed.remove("feedtable".into()).unwrap(); feed.into_iter() .map(|table| { table.into_iter() .map(|(tool, stats)| { (tool.parse().unwrap(), stats) }) .collect() }) .collect::>>() }; } #[derive(Debug, Copy, Clone)] pub enum ItemParseError { InvalidMagType, InvalidMagBytes, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, enum_utils::FromStr, derive_more::Display)] pub enum MagType { Mag, Varuna, Mitra, Surya, Vayu, Varaha, Kama, Ushasu, Apsaras, Kumara, Kaitabha, Tapas, Bhirava, Kalki, Rudra, Marutah, Yaksa, Sita, Garuda, Nandin, Ashvinau, Ribhava, Soma, Ila, Durga, Vritra, Namuci, Sumba, Naga, Pitri, Kabanda, Ravana, Marica, Soniti, Preta, Andhaka, Bana, Naraka, Madhu, Churel, Robochao, OpaOpa, Pian, Chao, ChuChu, KapuKapu, AngelsWing, DevilsWing, Elenor, MarkIII, MasterSystem, Genesis, SegaSaturn, Dreamcast, Hamburger, PanzersTail, DevilsTail, Deva, Rati, Savitri, Rukmin, Pushan, Diwari, Sato, Bhima, Nidra, GeungSi, Tellusis, StrikerUnit, Pioneer, Puyo, Moro, Rappy, Yahoo, GaelGiel, Agastya, } impl MagType { pub fn value(&self) -> [u8; 3] { match self { MagType::Mag => [0x02, 0x00, 0x00], MagType::Varuna => [0x02, 0x01, 0x00], MagType::Mitra => [0x02, 0x02, 0x00], MagType::Surya => [0x02, 0x03, 0x00], MagType::Vayu => [0x02, 0x04, 0x00], MagType::Varaha => [0x02, 0x05, 0x00], MagType::Kama => [0x02, 0x06, 0x00], MagType::Ushasu => [0x02, 0x07, 0x00], MagType::Apsaras => [0x02, 0x08, 0x00], MagType::Kumara => [0x02, 0x09, 0x00], MagType::Kaitabha => [0x02, 0x0A, 0x00], MagType::Tapas => [0x02, 0x0B, 0x00], MagType::Bhirava => [0x02, 0x0C, 0x00], MagType::Kalki => [0x02, 0x0D, 0x00], MagType::Rudra => [0x02, 0x0E, 0x00], MagType::Marutah => [0x02, 0x0F, 0x00], MagType::Yaksa => [0x02, 0x10, 0x00], MagType::Sita => [0x02, 0x11, 0x00], MagType::Garuda => [0x02, 0x12, 0x00], MagType::Nandin => [0x02, 0x13, 0x00], MagType::Ashvinau => [0x02, 0x14, 0x00], MagType::Ribhava => [0x02, 0x15, 0x00], MagType::Soma => [0x02, 0x16, 0x00], MagType::Ila => [0x02, 0x17, 0x00], MagType::Durga => [0x02, 0x18, 0x00], MagType::Vritra => [0x02, 0x19, 0x00], MagType::Namuci => [0x02, 0x1A, 0x00], MagType::Sumba => [0x02, 0x1B, 0x00], MagType::Naga => [0x02, 0x1C, 0x00], MagType::Pitri => [0x02, 0x1D, 0x00], MagType::Kabanda => [0x02, 0x1E, 0x00], MagType::Ravana => [0x02, 0x1F, 0x00], MagType::Marica => [0x02, 0x20, 0x00], MagType::Soniti => [0x02, 0x21, 0x00], MagType::Preta => [0x02, 0x22, 0x00], MagType::Andhaka => [0x02, 0x23, 0x00], MagType::Bana => [0x02, 0x24, 0x00], MagType::Naraka => [0x02, 0x25, 0x00], MagType::Madhu => [0x02, 0x26, 0x00], MagType::Churel => [0x02, 0x27, 0x00], MagType::Robochao => [0x02, 0x28, 0x00], MagType::OpaOpa => [0x02, 0x29, 0x00], MagType::Pian => [0x02, 0x2A, 0x00], MagType::Chao => [0x02, 0x2B, 0x00], MagType::ChuChu => [0x02, 0x2C, 0x00], MagType::KapuKapu => [0x02, 0x2D, 0x00], MagType::AngelsWing => [0x02, 0x2E, 0x00], MagType::DevilsWing => [0x02, 0x2F, 0x00], MagType::Elenor => [0x02, 0x30, 0x00], MagType::MarkIII => [0x02, 0x31, 0x00], MagType::MasterSystem => [0x02, 0x32, 0x00], MagType::Genesis => [0x02, 0x33, 0x00], MagType::SegaSaturn => [0x02, 0x34, 0x00], MagType::Dreamcast => [0x02, 0x35, 0x00], MagType::Hamburger => [0x02, 0x36, 0x00], MagType::PanzersTail => [0x02, 0x37, 0x00], MagType::DevilsTail => [0x02, 0x38, 0x00], MagType::Deva => [0x02, 0x39, 0x00], MagType::Rati => [0x02, 0x3A, 0x00], MagType::Savitri => [0x02, 0x3B, 0x00], MagType::Rukmin => [0x02, 0x3C, 0x00], MagType::Pushan => [0x02, 0x3D, 0x00], MagType::Diwari => [0x02, 0x3E, 0x00], MagType::Sato => [0x02, 0x3F, 0x00], MagType::Bhima => [0x02, 0x40, 0x00], MagType::Nidra => [0x02, 0x41, 0x00], MagType::GeungSi => [0x02, 0x42, 0x00], MagType::Tellusis => [0x02, 0x44, 0x00], MagType::StrikerUnit => [0x02, 0x45, 0x00], MagType::Pioneer => [0x02, 0x46, 0x00], MagType::Puyo => [0x02, 0x47, 0x00], MagType::Moro => [0x02, 0x48, 0x00], MagType::Rappy => [0x02, 0x49, 0x00], MagType::Yahoo => [0x02, 0x4A, 0x00], MagType::GaelGiel => [0x02, 0x4B, 0x00], MagType::Agastya => [0x02, 0x4C, 0x00], } } pub fn parse_type(data: [u8; 3]) -> Result { match data { [0x02, 0x00, 0x00] => Ok(MagType::Mag), [0x02, 0x01, 0x00] => Ok(MagType::Varuna), [0x02, 0x02, 0x00] => Ok(MagType::Mitra), [0x02, 0x03, 0x00] => Ok(MagType::Surya), [0x02, 0x04, 0x00] => Ok(MagType::Vayu), [0x02, 0x05, 0x00] => Ok(MagType::Varaha), [0x02, 0x06, 0x00] => Ok(MagType::Kama), [0x02, 0x07, 0x00] => Ok(MagType::Ushasu), [0x02, 0x08, 0x00] => Ok(MagType::Apsaras), [0x02, 0x09, 0x00] => Ok(MagType::Kumara), [0x02, 0x0A, 0x00] => Ok(MagType::Kaitabha), [0x02, 0x0B, 0x00] => Ok(MagType::Tapas), [0x02, 0x0C, 0x00] => Ok(MagType::Bhirava), [0x02, 0x0D, 0x00] => Ok(MagType::Kalki), [0x02, 0x0E, 0x00] => Ok(MagType::Rudra), [0x02, 0x0F, 0x00] => Ok(MagType::Marutah), [0x02, 0x10, 0x00] => Ok(MagType::Yaksa), [0x02, 0x11, 0x00] => Ok(MagType::Sita), [0x02, 0x12, 0x00] => Ok(MagType::Garuda), [0x02, 0x13, 0x00] => Ok(MagType::Nandin), [0x02, 0x14, 0x00] => Ok(MagType::Ashvinau), [0x02, 0x15, 0x00] => Ok(MagType::Ribhava), [0x02, 0x16, 0x00] => Ok(MagType::Soma), [0x02, 0x17, 0x00] => Ok(MagType::Ila), [0x02, 0x18, 0x00] => Ok(MagType::Durga), [0x02, 0x19, 0x00] => Ok(MagType::Vritra), [0x02, 0x1A, 0x00] => Ok(MagType::Namuci), [0x02, 0x1B, 0x00] => Ok(MagType::Sumba), [0x02, 0x1C, 0x00] => Ok(MagType::Naga), [0x02, 0x1D, 0x00] => Ok(MagType::Pitri), [0x02, 0x1E, 0x00] => Ok(MagType::Kabanda), [0x02, 0x1F, 0x00] => Ok(MagType::Ravana), [0x02, 0x20, 0x00] => Ok(MagType::Marica), [0x02, 0x21, 0x00] => Ok(MagType::Soniti), [0x02, 0x22, 0x00] => Ok(MagType::Preta), [0x02, 0x23, 0x00] => Ok(MagType::Andhaka), [0x02, 0x24, 0x00] => Ok(MagType::Bana), [0x02, 0x25, 0x00] => Ok(MagType::Naraka), [0x02, 0x26, 0x00] => Ok(MagType::Madhu), [0x02, 0x27, 0x00] => Ok(MagType::Churel), [0x02, 0x28, 0x00] => Ok(MagType::Robochao), [0x02, 0x29, 0x00] => Ok(MagType::OpaOpa), [0x02, 0x2A, 0x00] => Ok(MagType::Pian), [0x02, 0x2B, 0x00] => Ok(MagType::Chao), [0x02, 0x2C, 0x00] => Ok(MagType::ChuChu), [0x02, 0x2D, 0x00] => Ok(MagType::KapuKapu), [0x02, 0x2E, 0x00] => Ok(MagType::AngelsWing), [0x02, 0x2F, 0x00] => Ok(MagType::DevilsWing), [0x02, 0x30, 0x00] => Ok(MagType::Elenor), [0x02, 0x31, 0x00] => Ok(MagType::MarkIII), [0x02, 0x32, 0x00] => Ok(MagType::MasterSystem), [0x02, 0x33, 0x00] => Ok(MagType::Genesis), [0x02, 0x34, 0x00] => Ok(MagType::SegaSaturn), [0x02, 0x35, 0x00] => Ok(MagType::Dreamcast), [0x02, 0x36, 0x00] => Ok(MagType::Hamburger), [0x02, 0x37, 0x00] => Ok(MagType::PanzersTail), [0x02, 0x38, 0x00] => Ok(MagType::DevilsTail), [0x02, 0x39, 0x00] => Ok(MagType::Deva), [0x02, 0x3A, 0x00] => Ok(MagType::Rati), [0x02, 0x3B, 0x00] => Ok(MagType::Savitri), [0x02, 0x3C, 0x00] => Ok(MagType::Rukmin), [0x02, 0x3D, 0x00] => Ok(MagType::Pushan), [0x02, 0x3E, 0x00] => Ok(MagType::Diwari), [0x02, 0x3F, 0x00] => Ok(MagType::Sato), [0x02, 0x40, 0x00] => Ok(MagType::Bhima), [0x02, 0x41, 0x00] => Ok(MagType::Nidra), [0x02, 0x42, 0x00] => Ok(MagType::GeungSi), [0x02, 0x44, 0x00] => Ok(MagType::Tellusis), [0x02, 0x45, 0x00] => Ok(MagType::StrikerUnit), [0x02, 0x46, 0x00] => Ok(MagType::Pioneer), [0x02, 0x47, 0x00] => Ok(MagType::Puyo), [0x02, 0x48, 0x00] => Ok(MagType::Moro), [0x02, 0x49, 0x00] => Ok(MagType::Rappy), [0x02, 0x4A, 0x00] => Ok(MagType::Yahoo), [0x02, 0x4B, 0x00] => Ok(MagType::GaelGiel), [0x02, 0x4C, 0x00] => Ok(MagType::Agastya), _ => Err(ItemParseError::InvalidMagType), } } } #[derive(Debug, Clone, PartialEq)] pub enum MagModifier { FeedMag{ food: ToolType, }, BankMag, // when putting a mag in the bank it truncates the values which has applications when raising degenerate mags MagCell(ToolType), } #[derive(Debug, Copy, Clone, PartialEq)] pub enum PhotonBlast { Farlla, Estlla, Leilla, Pilla, Golla, MyllaYoulla, } #[derive(Debug, Clone, PartialEq)] pub struct Mag { pub mag: MagType, def: u16, pow: u16, dex: u16, mnd: u16, pub synchro: u8, iq: u8, photon_blast: [Option; 3], pub color: u8, modifiers: Vec, } impl Mag { pub fn baby_mag(skin: u16) -> Mag { Mag { mag: MagType::Mag, def: 500, pow: 0, dex: 0, mnd: 0, synchro: 20, iq: 0, photon_blast: [None; 3], color: (skin % 18) as u8, modifiers: Vec::new(), } } pub fn as_bytes(&self) -> [u8; 16] { let mut result = [0; 16]; result[0..3].copy_from_slice(&self.mag.value()); result[3] = self.photon_blast_value(); result[4..6].copy_from_slice(&self.def.to_le_bytes()); result[6..8].copy_from_slice(&self.pow.to_le_bytes()); result[8..10].copy_from_slice(&self.dex.to_le_bytes()); result[10..12].copy_from_slice(&self.mnd.to_le_bytes()); result[12] = self.synchro; result[13] = self.iq; result[14] = self.photon_blast_count(); result[15] = self.color; result } fn photon_blast_value(&self) -> u8 { let mut photon_blast_list = vec![PhotonBlast::Farlla, PhotonBlast::Estlla, PhotonBlast::Golla, PhotonBlast::Pilla, PhotonBlast::Leilla, PhotonBlast::MyllaYoulla]; let mut photon_blast: u8 = 0; if let Some(ref pb_mid) = self.photon_blast[0] { match *pb_mid { PhotonBlast::Farlla => {}, PhotonBlast::Estlla => photon_blast |= 1, PhotonBlast::Golla => photon_blast |= 2, PhotonBlast::Pilla => photon_blast |= 3, PhotonBlast::Leilla => photon_blast |= 4, PhotonBlast::MyllaYoulla => photon_blast |= 5, } photon_blast_list.retain(|k| k != pb_mid); } if let Some(ref pb_right) = self.photon_blast[1] { match *pb_right { PhotonBlast::Farlla => {} PhotonBlast::Estlla => photon_blast |= 1 << 3, PhotonBlast::Golla => photon_blast |= 2 << 3, PhotonBlast::Pilla => photon_blast |= 3 << 3, PhotonBlast::Leilla => photon_blast |= 4 << 3, PhotonBlast::MyllaYoulla => photon_blast |= 5 << 3, } photon_blast_list.retain(|k| k != pb_right); } if let Some(ref pb_left) = self.photon_blast[2] { if let Some(pos) = photon_blast_list.iter().position(|k| k == pb_left) { photon_blast |= (pos as u8) << 6; }; } photon_blast } fn photon_blast_count(&self) -> u8 { let mut count = 0; for i in 0..3 { if let Some(_) = self.photon_blast[i] { count |= 1 << i }; } count } pub fn from_bytes(data: [u8; 16]) -> Result { let m = MagType::parse_type([data[0], data[1], data[2]]); if m.is_ok() { let mut def = u16::from_le_bytes([data[4], data[5]]); let mut pow = u16::from_le_bytes([data[6], data[7]]); let mut dex = u16::from_le_bytes([data[8], data[9]]); let mut mind = u16::from_le_bytes([data[10], data[11]]); if (def/100 + dex/100 + pow/100 + mind/100) > 200 { def = 0; pow = 0; dex = 0; mind = 0; } let sync = data[12] % 121; // TODO: handle invalid values. let iq = data[13] % 201; // TODO: handle invalid values. Ok(Mag{ mag: m.unwrap(), def: def, pow: pow, dex: dex, mnd: mind, synchro: sync, iq: iq, photon_blast: [None, None, None], // TODO: actually get PBs from bytes color: data[15] % 18, modifiers: Vec::new(), }) } else { Err(ItemParseError::InvalidMagBytes) // TODO: error handling if wrong bytes are given } } #[cfg(test)] mod test { use super::*; use std::io::Read; #[test] fn test_load_mag_stats() { let mut f = std::fs::File::open("data/item_stats/mag_stats.toml").unwrap(); let mut s = String::new(); f.read_to_string(&mut s).unwrap(); let mags: HashMap = toml::from_str(&s).unwrap(); let _mags = mags.into_iter() .map(|(name, stats)| { (name.parse().unwrap(), stats) }) .collect::>(); } #[test] fn test_load_mag_feed_table() { let mut f = std::fs::File::open("data/item_stats/mag_feed_table.toml").unwrap(); let mut s = String::new(); f.read_to_string(&mut s).unwrap(); let mut feed: HashMap>> = toml::from_str(&s).unwrap(); let feed = feed.remove("feedtable".into()).unwrap(); let _feed = feed.into_iter() .map(|table| { table.into_iter() .map(|(tool, stats)| { (tool.parse().unwrap(), stats) }) .collect() }) .collect::>>(); } }