use super::api::{Skill, Specialization}; use std::{fmt, str::FromStr}; /// The profession of the template. /// /// Can be cast to an `u8` to get the right ID for building chat links. #[repr(u8)] #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub enum Profession { Guardian = 1, Warrior = 2, Engineer = 3, Ranger = 4, Thief = 5, Elementalist = 6, Mesmer = 7, Necromancer = 8, Revenant = 9, } impl fmt::Display for Profession { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self, f) } } impl FromStr for Profession { type Err = (); fn from_str(s: &str) -> Result { match s { "Guardian" => Ok(Profession::Guardian), "Warrior" => Ok(Profession::Warrior), "Engineer" => Ok(Profession::Engineer), "Ranger" => Ok(Profession::Ranger), "Thief" => Ok(Profession::Thief), "Elementalist" => Ok(Profession::Elementalist), "Mesmer" => Ok(Profession::Mesmer), "Necromancer" => Ok(Profession::Necromancer), "Revenant" => Ok(Profession::Revenant), _ => Err(()), } } } /// Represents the selected trait. #[repr(u8)] #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub enum TraitChoice { None = 0, Top = 1, Middle = 2, Bottom = 3, } impl FromStr for TraitChoice { type Err = (); fn from_str(s: &str) -> Result { let lower = s.to_lowercase(); match &lower as &str { "" | "none" => Ok(TraitChoice::None), "top" => Ok(TraitChoice::Top), "mid" | "middle" => Ok(TraitChoice::Middle), "bot" | "bottom" => Ok(TraitChoice::Bottom), _ => Err(()), } } } /// Represents a traitline. /// /// A traitline consists of the chosen specialization including 3 possible trait choices. pub type Traitline = (Specialization, [TraitChoice; 3]); pub const SKILL_COUNT: usize = 5; pub const TRAITLINE_COUNT: usize = 3; /// Represents a build template. /// /// This struct is made with the same limitations as the game imposes. That is, even though the /// renderer can support more than three traitlines, this template will only allow you to take /// three. #[derive(Debug)] pub struct BuildTemplate { /// Profession of this build. profession: Profession, /// The skills of the build. /// /// Each slot can either contain a slot or be empty. A maximum of 5 skills are allowed (heal, 3 /// utilities and elite). skills: [Option; SKILL_COUNT], /// The traitlines of the build. traitlines: [Option; TRAITLINE_COUNT], } impl BuildTemplate { /// Returns a template without any skills or traitlines. pub fn empty(profession: Profession) -> BuildTemplate { BuildTemplate { profession, skills: [None, None, None, None, None], traitlines: [None, None, None], } } /// Creates a template with the given skills and traitlines. /// /// If there are more than 5 skills or 3 traitlines given, the function will return `None`. pub fn new( profession: Profession, skills: &[Skill], traitlines: &[Traitline], ) -> Option { if skills.len() > SKILL_COUNT { return None; } if traitlines.len() > TRAITLINE_COUNT { return None; } let mut skill_array = [None, None, None, None, None]; for (i, skill) in skills.iter().enumerate() { skill_array[i] = Some(skill.clone()); } let mut trait_array = [None, None, None]; for (i, traitline) in traitlines.iter().enumerate() { trait_array[i] = Some(traitline.clone()); } Some(BuildTemplate { profession, skills: skill_array, traitlines: trait_array, }) } /// Returns the profession of this build. pub fn profession(&self) -> Profession { self.profession } /// Returns the skills of this build. pub fn skills(&self) -> &[Option] { &self.skills } /// Returns the number of actually equipped skills. pub fn skill_count(&self) -> u32 { self.skills.iter().filter(|x| x.is_some()).count() as u32 } /// Returns the traitlines of this build. pub fn traitlines(&self) -> &[Option] { &self.traitlines } /// Returns the number of actually equipped specializations. pub fn traitline_count(&self) -> u32 { self.traitlines.iter().filter(|x| x.is_some()).count() as u32 } }