veloren_common/comp/body/
humanoid.rs

1use crate::{make_case_elim, make_proj_elim};
2use rand::{Rng, seq::SliceRandom, thread_rng};
3use serde::{Deserialize, Serialize};
4use serde_repr::{Deserialize_repr, Serialize_repr};
5
6make_proj_elim!(
7    body,
8    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
9    pub struct Body {
10        pub species: Species,
11        pub body_type: BodyType,
12        #[typed(pure)]
13        pub hair_style: u8,
14        #[typed(pure)]
15        pub beard: u8,
16        #[typed(pure)]
17        pub eyes: u8,
18        #[typed(pure)]
19        pub accessory: u8,
20        #[typed(pure)]
21        pub hair_color: u8,
22        #[typed(pure)]
23        pub skin: u8,
24        #[typed(pure)]
25        pub eye_color: u8,
26    }
27);
28
29impl Body {
30    pub fn random() -> Self {
31        let mut rng = thread_rng();
32        let species = *ALL_SPECIES.choose(&mut rng).unwrap();
33        Self::random_with(&mut rng, &species)
34    }
35
36    #[inline]
37    pub fn random_with(rng: &mut impl Rng, &species: &Species) -> Self {
38        let body_type = *ALL_BODY_TYPES.choose(rng).unwrap();
39        Self {
40            species,
41            body_type,
42            hair_style: rng.gen_range(0..species.num_hair_styles(body_type)),
43            beard: rng.gen_range(0..species.num_beards(body_type)),
44            accessory: rng.gen_range(0..species.num_accessories(body_type)),
45            hair_color: rng.gen_range(0..species.num_hair_colors()),
46            skin: rng.gen_range(0..species.num_skin_colors()),
47            eye_color: rng.gen_range(0..species.num_eye_colors()),
48            eyes: rng.gen_range(0..1), /* TODO Add a way to set specific head-segments for NPCs
49                                        * with the default being a random one */
50        }
51    }
52
53    pub fn validate(&mut self) {
54        self.hair_style = self
55            .hair_style
56            .min(self.species.num_hair_styles(self.body_type) - 1);
57        self.beard = self.beard.min(self.species.num_beards(self.body_type) - 1);
58        self.hair_color = self.hair_color.min(self.species.num_hair_colors() - 1);
59        self.skin = self.skin.min(self.species.num_skin_colors() - 1);
60        self.eyes = self.eyes.min(self.species.num_eyes(self.body_type) - 1);
61        self.eye_color = self.eye_color.min(self.species.num_eye_colors() - 1);
62        self.accessory = self
63            .accessory
64            .min(self.species.num_accessories(self.body_type) - 1);
65    }
66
67    pub fn height(&self) -> f32 { (20.0 / 9.0) * self.scaler() }
68
69    pub fn scaler(&self) -> f32 {
70        match (self.species, self.body_type) {
71            (Species::Orc, BodyType::Male) => 0.91,
72            (Species::Orc, BodyType::Female) => 0.81,
73            (Species::Human, BodyType::Male) => 0.81,
74            (Species::Human, BodyType::Female) => 0.76,
75            (Species::Elf, BodyType::Male) => 0.82,
76            (Species::Elf, BodyType::Female) => 0.76,
77            (Species::Dwarf, BodyType::Male) => 0.67,
78            (Species::Dwarf, BodyType::Female) => 0.62,
79            (Species::Draugr, BodyType::Male) => 0.78,
80            (Species::Draugr, BodyType::Female) => 0.72,
81            (Species::Danari, BodyType::Male) => 0.56,
82            (Species::Danari, BodyType::Female) => 0.56,
83        }
84    }
85}
86
87impl From<Body> for super::Body {
88    fn from(body: Body) -> Self { super::Body::Humanoid(body) }
89}
90
91make_case_elim!(
92    species,
93    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
94    #[repr(u32)]
95    pub enum Species {
96        Danari = 0,
97        Dwarf = 1,
98        Elf = 2,
99        Human = 3,
100        Orc = 4,
101        Draugr = 5,
102    }
103);
104
105/// Data representing per-species generic data.
106///
107/// NOTE: Deliberately don't (yet?) implement serialize.
108#[derive(Clone, Debug, Serialize, Deserialize)]
109pub struct AllSpecies<SpeciesMeta> {
110    pub danari: SpeciesMeta,
111    pub dwarf: SpeciesMeta,
112    pub elf: SpeciesMeta,
113    pub human: SpeciesMeta,
114    pub orc: SpeciesMeta,
115    pub draugr: SpeciesMeta,
116}
117
118impl<'a, SpeciesMeta> core::ops::Index<&'a Species> for AllSpecies<SpeciesMeta> {
119    type Output = SpeciesMeta;
120
121    #[inline]
122    fn index(&self, &index: &'a Species) -> &Self::Output {
123        match index {
124            Species::Danari => &self.danari,
125            Species::Dwarf => &self.dwarf,
126            Species::Elf => &self.elf,
127            Species::Human => &self.human,
128            Species::Orc => &self.orc,
129            Species::Draugr => &self.draugr,
130        }
131    }
132}
133
134pub const ALL_SPECIES: [Species; 6] = [
135    Species::Danari,
136    Species::Dwarf,
137    Species::Elf,
138    Species::Human,
139    Species::Orc,
140    Species::Draugr,
141];
142
143impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
144    type IntoIter = std::iter::Copied<std::slice::Iter<'static, Self::Item>>;
145    type Item = Species;
146
147    fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() }
148}
149
150// Skin colors
151pub const DANARI_SKIN_COLORS: [Skin; 7] = [
152    Skin::DanariOne,
153    Skin::DanariTwo,
154    Skin::DanariThree,
155    Skin::DanariFour,
156    Skin::DanariFive,
157    Skin::DanariSix,
158    Skin::DanariSeven,
159];
160pub const DWARF_SKIN_COLORS: [Skin; 14] = [
161    Skin::DwarfOne,
162    Skin::DwarfTwo,
163    Skin::DwarfThree,
164    Skin::DwarfFour,
165    Skin::DwarfFive,
166    Skin::DwarfSix,
167    Skin::DwarfSeven,
168    Skin::DwarfEight,
169    Skin::DwarfNine,
170    Skin::DwarfTen,
171    Skin::DwarfEleven,
172    Skin::DwarfTwelve,
173    Skin::DwarfThirteen,
174    Skin::DwarfFourteen,
175];
176pub const ELF_SKIN_COLORS: [Skin; 18] = [
177    Skin::ElfOne,
178    Skin::ElfTwo,
179    Skin::ElfThree,
180    Skin::ElfFour,
181    Skin::ElfFive,
182    Skin::ElfSix,
183    Skin::ElfSeven,
184    Skin::ElfEight,
185    Skin::ElfNine,
186    Skin::ElfTen,
187    Skin::ElfEleven,
188    Skin::ElfTwelve,
189    Skin::ElfThirteen,
190    Skin::ElfFourteen,
191    Skin::ElfFifteen,
192    Skin::ElfSixteen,
193    Skin::ElfSeventeen,
194    Skin::ElfEighteen,
195];
196pub const HUMAN_SKIN_COLORS: [Skin; 18] = [
197    Skin::HumanOne,
198    Skin::HumanTwo,
199    Skin::HumanThree,
200    Skin::HumanFour,
201    Skin::HumanFive,
202    Skin::HumanSix,
203    Skin::HumanSeven,
204    Skin::HumanEight,
205    Skin::HumanNine,
206    Skin::HumanTen,
207    Skin::HumanEleven,
208    Skin::HumanTwelve,
209    Skin::HumanThirteen,
210    Skin::HumanFourteen,
211    Skin::HumanFifteen,
212    Skin::HumanSixteen,
213    Skin::HumanSeventeen,
214    Skin::HumanEighteen,
215];
216pub const ORC_SKIN_COLORS: [Skin; 8] = [
217    Skin::OrcOne,
218    Skin::OrcTwo,
219    Skin::OrcThree,
220    Skin::OrcFour,
221    Skin::OrcFive,
222    Skin::OrcSix,
223    Skin::OrcSeven,
224    Skin::OrcEight,
225];
226pub const DRAUGR_SKIN_COLORS: [Skin; 9] = [
227    Skin::DraugrOne,
228    Skin::DraugrTwo,
229    Skin::DraugrThree,
230    Skin::DraugrFour,
231    Skin::DraugrFive,
232    Skin::DraugrSix,
233    Skin::DraugrSeven,
234    Skin::DraugrEight,
235    Skin::DraugrNine,
236];
237
238// Eye colors
239pub const DANARI_EYE_COLORS: [EyeColor; 4] = [
240    EyeColor::EmeraldGreen,
241    EyeColor::LoyalBrown,
242    EyeColor::RegalPurple,
243    EyeColor::ViciousRed,
244];
245pub const DWARF_EYE_COLORS: [EyeColor; 6] = [
246    EyeColor::AmberYellow,
247    EyeColor::CornflowerBlue,
248    EyeColor::LoyalBrown,
249    EyeColor::NobleBlue,
250    EyeColor::PineGreen,
251    EyeColor::RustBrown,
252];
253pub const ELF_EYE_COLORS: [EyeColor; 7] = [
254    EyeColor::AmberYellow,
255    EyeColor::BrightBrown,
256    EyeColor::EmeraldGreen,
257    EyeColor::NobleBlue,
258    EyeColor::SapphireBlue,
259    EyeColor::RegalPurple,
260    EyeColor::RubyRed,
261];
262pub const HUMAN_EYE_COLORS: [EyeColor; 5] = [
263    EyeColor::NobleBlue,
264    EyeColor::CornflowerBlue,
265    EyeColor::CuriousGreen,
266    EyeColor::LoyalBrown,
267    EyeColor::VigorousBlack,
268];
269pub const ORC_EYE_COLORS: [EyeColor; 6] = [
270    EyeColor::AmberYellow,
271    EyeColor::CornflowerBlue,
272    EyeColor::ExoticPurple,
273    EyeColor::LoyalBrown,
274    EyeColor::PineGreen,
275    EyeColor::RustBrown,
276];
277pub const DRAUGR_EYE_COLORS: [EyeColor; 6] = [
278    EyeColor::FrozenBlue,
279    EyeColor::GhastlyYellow,
280    EyeColor::MagicPurple,
281    EyeColor::PumpkinOrange,
282    EyeColor::ToxicGreen,
283    EyeColor::ViciousRed,
284];
285
286impl Species {
287    fn skin_colors(self) -> &'static [Skin] {
288        match self {
289            Species::Danari => &DANARI_SKIN_COLORS,
290            Species::Dwarf => &DWARF_SKIN_COLORS,
291            Species::Elf => &ELF_SKIN_COLORS,
292            Species::Human => &HUMAN_SKIN_COLORS,
293            Species::Orc => &ORC_SKIN_COLORS,
294            Species::Draugr => &DRAUGR_SKIN_COLORS,
295        }
296    }
297
298    fn eye_colors(self) -> &'static [EyeColor] {
299        match self {
300            Species::Danari => &DANARI_EYE_COLORS,
301            Species::Dwarf => &DWARF_EYE_COLORS,
302            Species::Elf => &ELF_EYE_COLORS,
303            Species::Human => &HUMAN_EYE_COLORS,
304            Species::Orc => &ORC_EYE_COLORS,
305            Species::Draugr => &DRAUGR_EYE_COLORS,
306        }
307    }
308
309    /// FIXME: This is a hack!  The only reason we need to do this is because
310    /// hair colors are currently just indices into an array, not enum
311    /// variants.  Once we have proper variants for hair colors, we won't
312    /// need to do this anymore, since we will use locally defined arrays to
313    /// represent per-species stuff (or have some other solution for validity).
314    pub fn num_hair_colors(self) -> u8 {
315        match self {
316            Species::Danari => 17,
317            Species::Dwarf => 21,
318            Species::Elf => 24,
319            Species::Human => 22,
320            Species::Orc => 13,
321            Species::Draugr => 25,
322        }
323    }
324
325    pub fn skin_color(self, val: u8) -> Skin {
326        self.skin_colors()
327            .get(val as usize)
328            .copied()
329            .unwrap_or(Skin::HumanThree)
330    }
331
332    pub fn num_skin_colors(self) -> u8 { self.skin_colors().len() as u8 }
333
334    pub fn eye_color(self, val: u8) -> EyeColor {
335        self.eye_colors()
336            .get(val as usize)
337            .copied()
338            .unwrap_or(EyeColor::NobleBlue)
339    }
340
341    pub fn num_eye_colors(self) -> u8 { self.eye_colors().len() as u8 }
342
343    pub fn num_hair_styles(self, body_type: BodyType) -> u8 {
344        match (self, body_type) {
345            (Species::Danari, BodyType::Female) => 15,
346            (Species::Danari, BodyType::Male) => 15,
347            (Species::Dwarf, BodyType::Female) => 15,
348            (Species::Dwarf, BodyType::Male) => 15,
349            (Species::Elf, BodyType::Female) => 22,
350            (Species::Elf, BodyType::Male) => 15,
351            (Species::Human, BodyType::Female) => 20,
352            (Species::Human, BodyType::Male) => 21,
353            (Species::Orc, BodyType::Female) => 15,
354            (Species::Orc, BodyType::Male) => 15,
355            (Species::Draugr, BodyType::Female) => 15,
356            (Species::Draugr, BodyType::Male) => 15,
357        }
358    }
359
360    pub fn num_accessories(self, body_type: BodyType) -> u8 {
361        match (self, body_type) {
362            (Species::Danari, BodyType::Female) => 7,
363            (Species::Danari, BodyType::Male) => 7,
364            (Species::Dwarf, BodyType::Female) => 7,
365            (Species::Dwarf, BodyType::Male) => 7,
366            (Species::Elf, BodyType::Female) => 6,
367            (Species::Elf, BodyType::Male) => 5,
368            (Species::Human, BodyType::Female) => 1,
369            (Species::Human, BodyType::Male) => 1,
370            (Species::Orc, BodyType::Female) => 9,
371            (Species::Orc, BodyType::Male) => 12,
372            (Species::Draugr, BodyType::Female) => 2,
373            (Species::Draugr, BodyType::Male) => 2,
374        }
375    }
376
377    pub fn num_eyebrows(self, _body_type: BodyType) -> u8 { 1 }
378
379    pub fn num_eyes(self, body_type: BodyType) -> u8 {
380        match (self, body_type) {
381            (Species::Danari, BodyType::Female) => 6,
382            (Species::Danari, BodyType::Male) => 8,
383            (Species::Dwarf, BodyType::Female) => 6,
384            (Species::Dwarf, BodyType::Male) => 9,
385            (Species::Elf, BodyType::Female) => 6,
386            (Species::Elf, BodyType::Male) => 8,
387            (Species::Human, BodyType::Female) => 6,
388            (Species::Human, BodyType::Male) => 7,
389            (Species::Orc, BodyType::Female) => 6,
390            (Species::Orc, BodyType::Male) => 2,
391            (Species::Draugr, BodyType::Female) => 3,
392            (Species::Draugr, BodyType::Male) => 8,
393        }
394    }
395
396    pub fn num_beards(self, body_type: BodyType) -> u8 {
397        match (self, body_type) {
398            (Species::Danari, BodyType::Female) => 1,
399            (Species::Danari, BodyType::Male) => 16,
400            (Species::Dwarf, BodyType::Female) => 1,
401            (Species::Dwarf, BodyType::Male) => 23,
402            (Species::Elf, BodyType::Female) => 1,
403            (Species::Elf, BodyType::Male) => 8,
404            (Species::Human, BodyType::Female) => 1,
405            (Species::Human, BodyType::Male) => 10,
406            (Species::Orc, BodyType::Female) => 1,
407            (Species::Orc, BodyType::Male) => 7,
408            (Species::Draugr, BodyType::Female) => 1,
409            (Species::Draugr, BodyType::Male) => 6,
410        }
411    }
412}
413
414make_case_elim!(
415    body_type,
416    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
417    #[repr(u32)]
418    pub enum BodyType {
419        Female = 0,
420        Male = 1,
421    }
422);
423
424pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male];
425
426make_case_elim!(
427    eye_color,
428    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr)]
429    #[repr(u32)]
430    pub enum EyeColor {
431        AmberOrange = 0,
432        AmberYellow = 1,
433        BrightBrown = 2,
434        CornflowerBlue = 3,
435        CuriousGreen = 4,
436        EmeraldGreen = 5,
437        ExoticPurple = 6,
438        FrozenBlue = 7,
439        GhastlyYellow = 8,
440        LoyalBrown = 9,
441        MagicPurple = 10,
442        NobleBlue = 11,
443        PineGreen = 12,
444        PumpkinOrange = 13,
445        RubyRed = 14,
446        RegalPurple = 15,
447        RustBrown = 16,
448        SapphireBlue = 17,
449        SulfurYellow = 18,
450        ToxicGreen = 19,
451        ViciousRed = 20,
452        VigorousBlack = 21,
453    }
454);
455
456make_case_elim!(
457    skin,
458    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr)]
459    #[repr(u32)]
460    pub enum Skin {
461        // Humans
462        HumanOne = 0,
463        HumanTwo = 1,
464        HumanThree = 2,
465        HumanFour = 3,
466        HumanFive = 4,
467        HumanSix = 5,
468        HumanSeven = 6,
469        HumanEight = 7,
470        HumanNine = 8,
471        HumanTen = 9,
472        HumanEleven = 10,
473        HumanTwelve = 11,
474        HumanThirteen = 12,
475        HumanFourteen = 13,
476        HumanFifteen = 14,
477        HumanSixteen = 15,
478        HumanSeventeen = 16,
479        HumanEighteen = 17,
480        // Dwarves
481        DwarfOne = 18,
482        DwarfTwo = 19,
483        DwarfThree = 20,
484        DwarfFour = 21,
485        DwarfFive = 22,
486        DwarfSix = 23,
487        DwarfSeven = 24,
488        DwarfEight = 25,
489        DwarfNine = 26,
490        DwarfTen = 27,
491        DwarfEleven = 28,
492        DwarfTwelve = 29,
493        DwarfThirteen = 30,
494        DwarfFourteen = 31,
495        // Elves
496        ElfOne = 32,
497        ElfTwo = 33,
498        ElfThree = 34,
499        ElfFour = 35,
500        ElfFive = 36,
501        ElfSix = 37,
502        ElfSeven = 38,
503        ElfEight = 39,
504        ElfNine = 40,
505        ElfTen = 41,
506        ElfEleven = 42,
507        ElfTwelve = 43,
508        ElfThirteen = 44,
509        ElfFourteen = 45,
510        ElfFifteen = 46,
511        ElfSixteen = 47,
512        ElfSeventeen = 48,
513        ElfEighteen = 49,
514        // Orcs
515        OrcOne = 50,
516        OrcTwo = 51,
517        OrcThree = 52,
518        OrcFour = 53,
519        OrcFive = 54,
520        OrcSix = 55,
521        OrcSeven = 56,
522        OrcEight = 57,
523        // Danaris
524        DanariOne = 58,
525        DanariTwo = 59,
526        DanariThree = 60,
527        DanariFour = 61,
528        DanariFive = 62,
529        DanariSix = 63,
530        DanariSeven = 64,
531        // Draugrs
532        DraugrOne = 65,
533        DraugrTwo = 66,
534        DraugrThree = 67,
535        DraugrFour = 68,
536        DraugrFive = 69,
537        DraugrSix = 70,
538        DraugrSeven = 71,
539        DraugrEight = 72,
540        DraugrNine = 73,
541    }
542);