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