use serde::{Serialize, Deserialize}; #[derive(Debug, Copy, Clone)] pub enum ItemParseError { InvalidUnitBytes, InvalidUnitType, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, enum_utils::FromStr, derive_more::Display, strum_macros::EnumIter)] pub enum UnitType { KnightPower, GeneralPower, OgrePower, GodPower, PriestMind, GeneralMind, AngelMind, GodMind, MarksmanArm, GeneralArm, ElfArm, GodArm, ThiefLegs, GeneralLegs, ElfLegs, GodLegs, DiggerHp, GeneralHp, DragonHp, GodHp, MagicianTp, GeneralTp, AngelTp, GodTp, WarriorBody, GeneralBody, MetalBody, GodBody, AngelLuck, GodLuck, MasterAbility, HeroAbility, GodAbility, ResistFire, ResistFlame, ResistBurning, ResistCold, ResistFreeze, ResistBlizzard, ResistShock, ResistThunder, ResistStorm, ResistLight, ResistSaint, ResistHoly, ResistDark, ResistEvil, ResistDevil, AllResist, SuperResist, PerfectResist, HpRestorate, HpGenerate, HpRevival, TpRestorate, TpGenerate, TpRevival, PbAmplifier, PbGenerate, PbCreate, WizardTechnique, DevilTechnique, GodTechnique, GeneralBattle, DevilBattle, GodBattle, CurePoison, CureParalysis, CureSlow, CureConfuse, CureFreeze, CureShock, YasakaniMagatama, V101, V501, V502, V801, Limiter, Adept, SwordsmanLore, ProofOfSwordSaint, Smartlink, DivineProtection, HeavenlyBattle, HeavenlyPower, HeavenlyMind, HeavenlyArms, HeavenlyLegs, HeavenlyBody, HeavenlyLuck, HeavenlyAbility, CenturionAbility, FriendRing, HeavenlyHp, HeavenlyTp, HeavenlyResist, HeavenlyTechnique, HpRessurection, TpRessurection, PbIncrease, } impl UnitType { pub fn value(&self) -> [u8; 3] { match self { UnitType::KnightPower => [0x01, 0x03, 0x00], UnitType::GeneralPower => [0x01, 0x03, 0x01], UnitType::OgrePower => [0x01, 0x03, 0x02], UnitType::GodPower => [0x01, 0x03, 0x03], UnitType::PriestMind => [0x01, 0x03, 0x04], UnitType::GeneralMind => [0x01, 0x03, 0x05], UnitType::AngelMind => [0x01, 0x03, 0x06], UnitType::GodMind => [0x01, 0x03, 0x07], UnitType::MarksmanArm => [0x01, 0x03, 0x08], UnitType::GeneralArm => [0x01, 0x03, 0x09], UnitType::ElfArm => [0x01, 0x03, 0x0A], UnitType::GodArm => [0x01, 0x03, 0x0B], UnitType::ThiefLegs => [0x01, 0x03, 0x0C], UnitType::GeneralLegs => [0x01, 0x03, 0x0D], UnitType::ElfLegs => [0x01, 0x03, 0x0E], UnitType::GodLegs => [0x01, 0x03, 0x0F], UnitType::DiggerHp => [0x01, 0x03, 0x10], UnitType::GeneralHp => [0x01, 0x03, 0x11], UnitType::DragonHp => [0x01, 0x03, 0x12], UnitType::GodHp => [0x01, 0x03, 0x13], UnitType::MagicianTp => [0x01, 0x03, 0x14], UnitType::GeneralTp => [0x01, 0x03, 0x15], UnitType::AngelTp => [0x01, 0x03, 0x16], UnitType::GodTp => [0x01, 0x03, 0x17], UnitType::WarriorBody => [0x01, 0x03, 0x18], UnitType::GeneralBody => [0x01, 0x03, 0x19], UnitType::MetalBody => [0x01, 0x03, 0x1A], UnitType::GodBody => [0x01, 0x03, 0x1B], UnitType::AngelLuck => [0x01, 0x03, 0x1C], UnitType::GodLuck => [0x01, 0x03, 0x1D], UnitType::MasterAbility => [0x01, 0x03, 0x1E], UnitType::HeroAbility => [0x01, 0x03, 0x1F], UnitType::GodAbility => [0x01, 0x03, 0x20], UnitType::ResistFire => [0x01, 0x03, 0x21], UnitType::ResistFlame => [0x01, 0x03, 0x22], UnitType::ResistBurning => [0x01, 0x03, 0x23], UnitType::ResistCold => [0x01, 0x03, 0x24], UnitType::ResistFreeze => [0x01, 0x03, 0x25], UnitType::ResistBlizzard => [0x01, 0x03, 0x26], UnitType::ResistShock => [0x01, 0x03, 0x27], UnitType::ResistThunder => [0x01, 0x03, 0x28], UnitType::ResistStorm => [0x01, 0x03, 0x29], UnitType::ResistLight => [0x01, 0x03, 0x2A], UnitType::ResistSaint => [0x01, 0x03, 0x2B], UnitType::ResistHoly => [0x01, 0x03, 0x2C], UnitType::ResistDark => [0x01, 0x03, 0x2D], UnitType::ResistEvil => [0x01, 0x03, 0x2E], UnitType::ResistDevil => [0x01, 0x03, 0x2F], UnitType::AllResist => [0x01, 0x03, 0x30], UnitType::SuperResist => [0x01, 0x03, 0x31], UnitType::PerfectResist => [0x01, 0x03, 0x32], UnitType::HpRestorate => [0x01, 0x03, 0x33], UnitType::HpGenerate => [0x01, 0x03, 0x34], UnitType::HpRevival => [0x01, 0x03, 0x35], UnitType::TpRestorate => [0x01, 0x03, 0x36], UnitType::TpGenerate => [0x01, 0x03, 0x37], UnitType::TpRevival => [0x01, 0x03, 0x38], UnitType::PbAmplifier => [0x01, 0x03, 0x39], UnitType::PbGenerate => [0x01, 0x03, 0x3A], UnitType::PbCreate => [0x01, 0x03, 0x3B], UnitType::WizardTechnique => [0x01, 0x03, 0x3C], UnitType::DevilTechnique => [0x01, 0x03, 0x3D], UnitType::GodTechnique => [0x01, 0x03, 0x3E], UnitType::GeneralBattle => [0x01, 0x03, 0x3F], UnitType::DevilBattle => [0x01, 0x03, 0x40], UnitType::GodBattle => [0x01, 0x03, 0x41], UnitType::CurePoison => [0x01, 0x03, 0x42], UnitType::CureParalysis => [0x01, 0x03, 0x43], UnitType::CureSlow => [0x01, 0x03, 0x44], UnitType::CureConfuse => [0x01, 0x03, 0x45], UnitType::CureFreeze => [0x01, 0x03, 0x46], UnitType::CureShock => [0x01, 0x03, 0x47], UnitType::YasakaniMagatama => [0x01, 0x03, 0x48], UnitType::V101 => [0x01, 0x03, 0x49], UnitType::V501 => [0x01, 0x03, 0x4A], UnitType::V502 => [0x01, 0x03, 0x4B], UnitType::V801 => [0x01, 0x03, 0x4C], UnitType::Limiter => [0x01, 0x03, 0x4D], UnitType::Adept => [0x01, 0x03, 0x4E], UnitType::SwordsmanLore => [0x01, 0x03, 0x4F], UnitType::ProofOfSwordSaint => [0x01, 0x03, 0x50], UnitType::Smartlink => [0x01, 0x03, 0x51], UnitType::DivineProtection => [0x01, 0x03, 0x52], UnitType::HeavenlyBattle => [0x01, 0x03, 0x53], UnitType::HeavenlyPower => [0x01, 0x03, 0x54], UnitType::HeavenlyMind => [0x01, 0x03, 0x55], UnitType::HeavenlyArms => [0x01, 0x03, 0x56], UnitType::HeavenlyLegs => [0x01, 0x03, 0x57], UnitType::HeavenlyBody => [0x01, 0x03, 0x58], UnitType::HeavenlyLuck => [0x01, 0x03, 0x59], UnitType::HeavenlyAbility => [0x01, 0x03, 0x5A], UnitType::CenturionAbility => [0x01, 0x03, 0x5B], UnitType::FriendRing => [0x01, 0x03, 0x5C], UnitType::HeavenlyHp => [0x01, 0x03, 0x5D], UnitType::HeavenlyTp => [0x01, 0x03, 0x5E], UnitType::HeavenlyResist => [0x01, 0x03, 0x5F], UnitType::HeavenlyTechnique => [0x01, 0x03, 0x60], UnitType::HpRessurection => [0x01, 0x03, 0x61], UnitType::TpRessurection => [0x01, 0x03, 0x62], UnitType::PbIncrease => [0x01, 0x03, 0x63], } } pub fn parse_type(data: [u8; 3]) -> Result { match data { [0x01, 0x03, 0x00] => Ok(UnitType::KnightPower), [0x01, 0x03, 0x01] => Ok(UnitType::GeneralPower), [0x01, 0x03, 0x02] => Ok(UnitType::OgrePower), [0x01, 0x03, 0x03] => Ok(UnitType::GodPower), [0x01, 0x03, 0x04] => Ok(UnitType::PriestMind), [0x01, 0x03, 0x05] => Ok(UnitType::GeneralMind), [0x01, 0x03, 0x06] => Ok(UnitType::AngelMind), [0x01, 0x03, 0x07] => Ok(UnitType::GodMind), [0x01, 0x03, 0x08] => Ok(UnitType::MarksmanArm), [0x01, 0x03, 0x09] => Ok(UnitType::GeneralArm), [0x01, 0x03, 0x0A] => Ok(UnitType::ElfArm), [0x01, 0x03, 0x0B] => Ok(UnitType::GodArm), [0x01, 0x03, 0x0C] => Ok(UnitType::ThiefLegs), [0x01, 0x03, 0x0D] => Ok(UnitType::GeneralLegs), [0x01, 0x03, 0x0E] => Ok(UnitType::ElfLegs), [0x01, 0x03, 0x0F] => Ok(UnitType::GodLegs), [0x01, 0x03, 0x10] => Ok(UnitType::DiggerHp), [0x01, 0x03, 0x11] => Ok(UnitType::GeneralHp), [0x01, 0x03, 0x12] => Ok(UnitType::DragonHp), [0x01, 0x03, 0x13] => Ok(UnitType::GodHp), [0x01, 0x03, 0x14] => Ok(UnitType::MagicianTp), [0x01, 0x03, 0x15] => Ok(UnitType::GeneralTp), [0x01, 0x03, 0x16] => Ok(UnitType::AngelTp), [0x01, 0x03, 0x17] => Ok(UnitType::GodTp), [0x01, 0x03, 0x18] => Ok(UnitType::WarriorBody), [0x01, 0x03, 0x19] => Ok(UnitType::GeneralBody), [0x01, 0x03, 0x1A] => Ok(UnitType::MetalBody), [0x01, 0x03, 0x1B] => Ok(UnitType::GodBody), [0x01, 0x03, 0x1C] => Ok(UnitType::AngelLuck), [0x01, 0x03, 0x1D] => Ok(UnitType::GodLuck), [0x01, 0x03, 0x1E] => Ok(UnitType::MasterAbility), [0x01, 0x03, 0x1F] => Ok(UnitType::HeroAbility), [0x01, 0x03, 0x20] => Ok(UnitType::GodAbility), [0x01, 0x03, 0x21] => Ok(UnitType::ResistFire), [0x01, 0x03, 0x22] => Ok(UnitType::ResistFlame), [0x01, 0x03, 0x23] => Ok(UnitType::ResistBurning), [0x01, 0x03, 0x24] => Ok(UnitType::ResistCold), [0x01, 0x03, 0x25] => Ok(UnitType::ResistFreeze), [0x01, 0x03, 0x26] => Ok(UnitType::ResistBlizzard), [0x01, 0x03, 0x27] => Ok(UnitType::ResistShock), [0x01, 0x03, 0x28] => Ok(UnitType::ResistThunder), [0x01, 0x03, 0x29] => Ok(UnitType::ResistStorm), [0x01, 0x03, 0x2A] => Ok(UnitType::ResistLight), [0x01, 0x03, 0x2B] => Ok(UnitType::ResistSaint), [0x01, 0x03, 0x2C] => Ok(UnitType::ResistHoly), [0x01, 0x03, 0x2D] => Ok(UnitType::ResistDark), [0x01, 0x03, 0x2E] => Ok(UnitType::ResistEvil), [0x01, 0x03, 0x2F] => Ok(UnitType::ResistDevil), [0x01, 0x03, 0x30] => Ok(UnitType::AllResist), [0x01, 0x03, 0x31] => Ok(UnitType::SuperResist), [0x01, 0x03, 0x32] => Ok(UnitType::PerfectResist), [0x01, 0x03, 0x33] => Ok(UnitType::HpRestorate), [0x01, 0x03, 0x34] => Ok(UnitType::HpGenerate), [0x01, 0x03, 0x35] => Ok(UnitType::HpRevival), [0x01, 0x03, 0x36] => Ok(UnitType::TpRestorate), [0x01, 0x03, 0x37] => Ok(UnitType::TpGenerate), [0x01, 0x03, 0x38] => Ok(UnitType::TpRevival), [0x01, 0x03, 0x39] => Ok(UnitType::PbAmplifier), [0x01, 0x03, 0x3A] => Ok(UnitType::PbGenerate), [0x01, 0x03, 0x3B] => Ok(UnitType::PbCreate), [0x01, 0x03, 0x3C] => Ok(UnitType::WizardTechnique), [0x01, 0x03, 0x3D] => Ok(UnitType::DevilTechnique), [0x01, 0x03, 0x3E] => Ok(UnitType::GodTechnique), [0x01, 0x03, 0x3F] => Ok(UnitType::GeneralBattle), [0x01, 0x03, 0x40] => Ok(UnitType::DevilBattle), [0x01, 0x03, 0x41] => Ok(UnitType::GodBattle), [0x01, 0x03, 0x42] => Ok(UnitType::CurePoison), [0x01, 0x03, 0x43] => Ok(UnitType::CureParalysis), [0x01, 0x03, 0x44] => Ok(UnitType::CureSlow), [0x01, 0x03, 0x45] => Ok(UnitType::CureConfuse), [0x01, 0x03, 0x46] => Ok(UnitType::CureFreeze), [0x01, 0x03, 0x47] => Ok(UnitType::CureShock), [0x01, 0x03, 0x48] => Ok(UnitType::YasakaniMagatama), [0x01, 0x03, 0x49] => Ok(UnitType::V101), [0x01, 0x03, 0x4A] => Ok(UnitType::V501), [0x01, 0x03, 0x4B] => Ok(UnitType::V502), [0x01, 0x03, 0x4C] => Ok(UnitType::V801), [0x01, 0x03, 0x4D] => Ok(UnitType::Limiter), [0x01, 0x03, 0x4E] => Ok(UnitType::Adept), [0x01, 0x03, 0x4F] => Ok(UnitType::SwordsmanLore), [0x01, 0x03, 0x50] => Ok(UnitType::ProofOfSwordSaint), [0x01, 0x03, 0x51] => Ok(UnitType::Smartlink), [0x01, 0x03, 0x52] => Ok(UnitType::DivineProtection), [0x01, 0x03, 0x53] => Ok(UnitType::HeavenlyBattle), [0x01, 0x03, 0x54] => Ok(UnitType::HeavenlyPower), [0x01, 0x03, 0x55] => Ok(UnitType::HeavenlyMind), [0x01, 0x03, 0x56] => Ok(UnitType::HeavenlyArms), [0x01, 0x03, 0x57] => Ok(UnitType::HeavenlyLegs), [0x01, 0x03, 0x58] => Ok(UnitType::HeavenlyBody), [0x01, 0x03, 0x59] => Ok(UnitType::HeavenlyLuck), [0x01, 0x03, 0x5A] => Ok(UnitType::HeavenlyAbility), [0x01, 0x03, 0x5B] => Ok(UnitType::CenturionAbility), [0x01, 0x03, 0x5C] => Ok(UnitType::FriendRing), [0x01, 0x03, 0x5D] => Ok(UnitType::HeavenlyHp), [0x01, 0x03, 0x5E] => Ok(UnitType::HeavenlyTp), [0x01, 0x03, 0x5F] => Ok(UnitType::HeavenlyResist), [0x01, 0x03, 0x60] => Ok(UnitType::HeavenlyTechnique), [0x01, 0x03, 0x61] => Ok(UnitType::HpRessurection), [0x01, 0x03, 0x62] => Ok(UnitType::TpRessurection), [0x01, 0x03, 0x63] => Ok(UnitType::PbIncrease), _ => Err(ItemParseError::InvalidUnitType), } } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum UnitModifier { PlusPlus, Plus, Minus, MinusMinus, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Unit { pub unit: UnitType, pub modifier: Option, } impl Unit { pub fn as_bytes(&self) -> [u8; 16] { let mut result = [0; 16]; result[0..3].copy_from_slice(&self.unit.value()); if let Some(modifier) = self.modifier { match modifier { UnitModifier::PlusPlus => { result[6] = 2; }, UnitModifier::Plus => { result[6] = 1; }, UnitModifier::Minus => { result[6] = 0xFF; result[7] = 0xFF; }, UnitModifier::MinusMinus => { result[6] = 0xFE; result[7] = 0xFF; }, } } result } pub fn from_bytes(data: [u8; 16]) -> Result { let u = UnitType::parse_type([data[0], data[1], data[2]]); if let Ok(u) = u { let m = match u16::from_le_bytes([data[6], data[7]]) { 0x02 => Some(UnitModifier::PlusPlus), 0x01 => Some(UnitModifier::Plus), 0xFEFF => Some(UnitModifier::Minus), 0xFFFF => Some(UnitModifier::MinusMinus), _ => None, }; Ok(Unit{ unit: u, modifier: m, }) } else { Err(ItemParseError::InvalidUnitBytes) // TODO: error handling if wrong bytes are given } } pub fn is_rare_item(self) -> bool { matches!( self.unit, UnitType::GodPower | UnitType::GodMind | UnitType::GodArm | UnitType::GodLegs | UnitType::GodHp | UnitType::GodTp | UnitType::GodBody | UnitType::GodLuck | UnitType::HeroAbility | UnitType::GodAbility | UnitType::AllResist | UnitType::SuperResist | UnitType::PerfectResist | UnitType::HpRevival | UnitType::TpRevival | UnitType::PbAmplifier | UnitType::PbGenerate | UnitType::PbCreate | UnitType::DevilTechnique | UnitType::GodTechnique | UnitType::DevilBattle | UnitType::GodBattle | UnitType::CurePoison | UnitType::CureParalysis | UnitType::CureSlow | UnitType::CureConfuse | UnitType::CureFreeze | UnitType::CureShock | UnitType::YasakaniMagatama | UnitType::V101 | UnitType::V501 | UnitType::V502 | UnitType::V801 | UnitType::Limiter | UnitType::Adept | UnitType::SwordsmanLore | UnitType::ProofOfSwordSaint | UnitType::Smartlink | UnitType::DivineProtection | UnitType::HeavenlyBattle | UnitType::HeavenlyPower | UnitType::HeavenlyMind | UnitType::HeavenlyArms | UnitType::HeavenlyLegs | UnitType::HeavenlyBody | UnitType::HeavenlyLuck | UnitType::HeavenlyAbility | UnitType::CenturionAbility | UnitType::FriendRing | UnitType::HeavenlyHp | UnitType::HeavenlyTp | UnitType::HeavenlyResist | UnitType::HeavenlyTechnique | UnitType::HpRessurection | UnitType::TpRessurection | UnitType::PbIncrease ) } pub fn modifier_stars(&self) -> i8 { match self.modifier { Some(UnitModifier::PlusPlus) => 1, Some(UnitModifier::Plus) => 1, Some(UnitModifier::Minus) => -1, Some(UnitModifier::MinusMinus) => -1, _ => 0, } } }