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