use serde::{Serialize, Deserialize}; // TODO: actually use this #[derive(Debug)] pub enum ItemParseError { InvalidESWeaponBytes, InvalidESWeaponType, InvalidESWeaponGrind, InvalidESWeaponSpecial, InvalidESWeaponName, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ESWeaponType { Saber = 0, Sword, Blade, Partisan, Slicer, Gun, Rifle, Mechgun, Shot, Can, Rod, Wand, Twin, Claw, Bazooka, Needle, Scythe, Hammer, Moon, Psychogun, Punch, Windmill, Harisen, Katana, JCutter, Swords = 0x35, Launcher, Cards, Knuckle, Axe, } impl ESWeaponType { pub fn to_value(&self) -> u8 { *self as u8 } pub fn from_value(value: u8) -> Result { match value { 0 => Ok(ESWeaponType::Saber), 1 => Ok(ESWeaponType::Sword), 2 => Ok(ESWeaponType::Blade), 3 => Ok(ESWeaponType::Partisan), 4 => Ok(ESWeaponType::Slicer), 5 => Ok(ESWeaponType::Gun), 6 => Ok(ESWeaponType::Rifle), 7 => Ok(ESWeaponType::Mechgun), 8 => Ok(ESWeaponType::Shot), 9 => Ok(ESWeaponType::Can), 10 => Ok(ESWeaponType::Rod), 11 => Ok(ESWeaponType::Wand), 12 => Ok(ESWeaponType::Twin), 13 => Ok(ESWeaponType::Claw), 14 => Ok(ESWeaponType::Bazooka), 15 => Ok(ESWeaponType::Needle), 16 => Ok(ESWeaponType::Scythe), 17 => Ok(ESWeaponType::Hammer), 18 => Ok(ESWeaponType::Moon), 19 => Ok(ESWeaponType::Psychogun), 20 => Ok(ESWeaponType::Punch), 21 => Ok(ESWeaponType::Windmill), 22 => Ok(ESWeaponType::Harisen), 23 => Ok(ESWeaponType::Katana), 24 => Ok(ESWeaponType::JCutter), 53 => Ok(ESWeaponType::Swords), 54 => Ok(ESWeaponType::Launcher), 55 => Ok(ESWeaponType::Cards), 56 => Ok(ESWeaponType::Knuckle), 57 => Ok(ESWeaponType::Axe), _ => Err(ItemParseError::InvalidESWeaponType), } } pub fn parse_type(data: [u8; 3]) -> Result { match data { [0x00, 0x70, 0x00] => Ok(ESWeaponType::Saber), [0x00, 0x71, 0x00] => Ok(ESWeaponType::Sword), [0x00, 0x72, 0x00] => Ok(ESWeaponType::Blade), [0x00, 0x73, 0x00] => Ok(ESWeaponType::Partisan), [0x00, 0x74, 0x00] => Ok(ESWeaponType::Slicer), [0x00, 0x75, 0x00] => Ok(ESWeaponType::Gun), [0x00, 0x76, 0x00] => Ok(ESWeaponType::Rifle), [0x00, 0x77, 0x00] => Ok(ESWeaponType::Mechgun), [0x00, 0x78, 0x00] => Ok(ESWeaponType::Shot), [0x00, 0x79, 0x00] => Ok(ESWeaponType::Can), [0x00, 0x7A, 0x00] => Ok(ESWeaponType::Rod), [0x00, 0x7B, 0x00] => Ok(ESWeaponType::Wand), [0x00, 0x7C, 0x00] => Ok(ESWeaponType::Twin), [0x00, 0x7D, 0x00] => Ok(ESWeaponType::Claw), [0x00, 0x7E, 0x00] => Ok(ESWeaponType::Bazooka), [0x00, 0x7F, 0x00] => Ok(ESWeaponType::Needle), [0x00, 0x80, 0x00] => Ok(ESWeaponType::Scythe), [0x00, 0x81, 0x00] => Ok(ESWeaponType::Hammer), [0x00, 0x82, 0x00] => Ok(ESWeaponType::Moon), [0x00, 0x83, 0x00] => Ok(ESWeaponType::Psychogun), [0x00, 0x84, 0x00] => Ok(ESWeaponType::Punch), [0x00, 0x85, 0x00] => Ok(ESWeaponType::Windmill), [0x00, 0x86, 0x00] => Ok(ESWeaponType::Harisen), [0x00, 0x87, 0x00] => Ok(ESWeaponType::Katana), [0x00, 0x88, 0x00] => Ok(ESWeaponType::JCutter), [0x00, 0xA5, 0x00] => Ok(ESWeaponType::Swords), [0x00, 0xA6, 0x00] => Ok(ESWeaponType::Launcher), [0x00, 0xA7, 0x00] => Ok(ESWeaponType::Cards), [0x00, 0xA8, 0x00] => Ok(ESWeaponType::Knuckle), [0x00, 0xA9, 0x00] => Ok(ESWeaponType::Axe), _ => Err(ItemParseError::InvalidESWeaponBytes), } } } #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum ESWeaponSpecial { Jellen = 1, Zalure, HPRegen, TPRegen, Burning, Tempest, Blizzard, Arrest, Chaos, Hell, Spirit, Berserk, Demons, Gush, Geist, Kings, } impl ESWeaponSpecial { pub fn to_value(&self) -> u8 { *self as u8 } pub fn from_value(value: u8) -> Result { match value{ 1 => Ok(ESWeaponSpecial::Jellen), 2 => Ok(ESWeaponSpecial::Zalure), 3 => Ok(ESWeaponSpecial::HPRegen), 4 => Ok(ESWeaponSpecial::TPRegen), 5 => Ok(ESWeaponSpecial::Burning), 6 => Ok(ESWeaponSpecial::Tempest), 7 => Ok(ESWeaponSpecial::Blizzard), 8 => Ok(ESWeaponSpecial::Arrest), 9 => Ok(ESWeaponSpecial::Chaos), 10 => Ok(ESWeaponSpecial::Hell), 11 => Ok(ESWeaponSpecial::Spirit), 12 => Ok(ESWeaponSpecial::Berserk), 13 => Ok(ESWeaponSpecial::Demons), 14 => Ok(ESWeaponSpecial::Gush), 15 => Ok(ESWeaponSpecial::Geist), 16 => Ok(ESWeaponSpecial::Kings), _ => Err(ItemParseError::InvalidESWeaponSpecial), } } } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ESWeapon { pub esweapon: ESWeaponType, pub special: Option, pub name: String, pub grind: u8, } impl ESWeapon { pub fn new(t: ESWeaponType) -> ESWeapon { ESWeapon { esweapon: t, special: None, name: "".to_owned(), grind: 0, } } pub fn bytes_from_name(&self) -> [u8; 6] { let mut result = [0u16; 3]; let mut letters = [0u8; 8]; letters[0..self.name.len()].clone_from_slice(&self.name.to_uppercase().clone().into_bytes()); for letter in letters.iter_mut() { *letter = *letter & 0x3F; } result[0] = 0x8000 + (0x20 * letters[0] as u16) + (letters[1] as u16); result[1] = 0x8000 + (0x400 * letters[2] as u16) + (0x20 * letters[3] as u16) + (letters[4] as u16); result[2] = 0x8000 + (0x400 * letters[5] as u16) + (0x20 * letters[6] as u16) + (letters[7] as u16); [result[0].to_be_bytes()[0], result[0].to_be_bytes()[1], result[1].to_be_bytes()[0], result[1].to_be_bytes()[1], result[2].to_be_bytes()[0], result[2].to_be_bytes()[1]] } // TODO: error handling, ensure name is never more than 8 pub fn name_from_bytes(namebytes: &[u8]) -> String { let mut name: Vec = Vec::with_capacity(8); name.extend_from_slice(namebytes); for _ in name.len()..name.capacity() { name.push(0); } let buf: [u16; 3] = [ u16::from_be_bytes([namebytes[0], namebytes[1]]), u16::from_be_bytes([namebytes[2], namebytes[3]]), u16::from_be_bytes([namebytes[4], namebytes[5]]), ]; name[0] = ((buf[0] - 0x8000) / 0x20 + 0x40) as u8; name[1] = ((buf[0] - 0x8000) % 0x20 + 0x40) as u8; name[2] = ((buf[1] - 0x8000) / 0x400 + 0x40) as u8; name[3] = (((buf[1] - 0x8000) % 0x400) / 0x20 + 0x40) as u8; name[4] = (((buf[1] - 0x8000) % 0x400) % 0x20 + 0x40) as u8; name[5] = ((buf[2] - 0x8000) / 0x400 + 0x40) as u8; name[6] = (((buf[2] - 0x8000) % 0x400) / 0x20 + 0x40) as u8; name[7] = (((buf[2] - 0x8000) % 0x400) % 0x20 + 0x40) as u8; name.retain(|&x| x > 0x40 && x < 0x5B); String::from_utf8(name).unwrap() } pub fn as_bytes(&self) -> [u8; 16] { let mut result = [0u8; 16]; result[1] = 0x70 + self.esweapon.to_value(); result[2] = self.special.map(|s| s.to_value()).unwrap_or(0); result[3] = self.grind; //result[4] = tekked/untekked flag result[6..12].clone_from_slice(&self.bytes_from_name()); result } // TODO: return Result pub fn from_bytes(bytes: [u8; 16]) -> ESWeapon { let esweapon = ESWeaponType::from_value(bytes[1] - 0x70).unwrap(); let special = ESWeaponSpecial::from_value(bytes[2]); let grind = bytes[3]; let name = ESWeapon::name_from_bytes(&bytes[6..12]); ESWeapon { esweapon: esweapon, special: special.ok(), grind: grind, name: name, } } } #[cfg(test)] mod test { use super::*; #[test] fn test_create_esweapon_from_bytes() { // JAKESERV BAZOOKA + 137 (Berserk) let weapon_bytes = [0x00, 0x7E, 0x0C, 0x89, 0x00, 0x00, 0x81, 0x41, 0xAC, 0xB3, 0x96, 0x56, 0x00, 0x00, 0x00, 0x00]; let testweapon = ESWeapon::from_bytes(weapon_bytes); assert_eq!(testweapon, ESWeapon { esweapon: ESWeaponType::Bazooka, special: Some(ESWeaponSpecial::Berserk), grind: 137u8, name: "JAKESERV".to_owned(), }); } #[test] fn test_create_bytes_from_esweapon() { // PSYCHO WAND + 72 (Chaos) let testweapon = ESWeapon { esweapon: ESWeaponType::Wand, special: Some(ESWeaponSpecial::Chaos), grind: 72u8, name: "PSYCHO".to_owned(), }; let bytes = testweapon.as_bytes(); assert_eq!(bytes, [0x00, 0x7B, 0x09, 0x48, 0x00, 0x00, 0x82, 0x13, 0xE4, 0x68, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00]); } #[test] fn test_create_bytes_from_higher_esweapon_type() { // YUGIOH CARDS + 105 (Spirit) let testweapon = ESWeapon { esweapon: ESWeaponType::Cards, special: Some(ESWeaponSpecial::Spirit), grind: 105u8, name: "YUGIOH".to_owned(), }; let bytes = testweapon.as_bytes(); assert_eq!(bytes, [0x00, 0xA7, 0x0B, 0x69, 0x00, 0x00, 0x83, 0x35, 0x9D, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00]); } }