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