use once_cell::sync::OnceCell; use serde::{Serialize, Deserialize}; use std::collections::BTreeMap; use crate::{ models::item::Sex }; use rand::seq::IteratorRandom; #[derive(Serialize, Deserialize, Eq, Ord, Clone, PartialEq, PartialOrd, Debug)] pub enum SpeciesType { Human, Dog } impl SpeciesType { pub fn sample_body_part(&self) -> BodyPart { let mut rng = rand::thread_rng(); species_info_map().get(&self) .and_then(|sp| sp.body_parts.iter().choose(&mut rng)) .unwrap_or(&BodyPart::Head).clone() } } #[derive(Eq, Ord, Clone, PartialEq, PartialOrd, Debug)] pub enum BodyPart { Head, Face, Chest, Back, Groin, Arms, Legs, Feet } impl BodyPart { pub fn display(&self, sex: Option) -> &'static str { use BodyPart::*; match self { Head => "head", Face => "face", Chest => match sex { Some(Sex::Female) => "breasts", _ => "chest", }, Back => "back", Groin => match sex { Some(Sex::Male) => "penis", Some(Sex::Female) => "vagina", _ => "groin" }, Arms => "arms", Legs => "legs", Feet => "feet" } } } pub struct SpeciesInfo { body_parts: Vec, } pub fn species_info_map() -> &'static BTreeMap { static INFOMAP: OnceCell> = OnceCell::new(); INFOMAP.get_or_init(|| { vec!( (SpeciesType::Human, SpeciesInfo { body_parts: vec!( BodyPart::Head, BodyPart::Face, BodyPart::Chest, BodyPart::Back, BodyPart::Groin, BodyPart::Arms, BodyPart::Legs, BodyPart::Feet ) } ), (SpeciesType::Dog, SpeciesInfo { body_parts: vec!( BodyPart::Head, BodyPart::Face, BodyPart::Chest, BodyPart::Back, BodyPart::Groin, BodyPart::Legs, BodyPart::Feet ) } ), ).into_iter().collect() }) }