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::{EnumIter, 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, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, EnumIter,
436 )]
437 #[repr(u32)]
438 pub enum BodyType {
439 Female = 0,
440 Male = 1,
441 }
442);
443
444pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male];
445
446make_case_elim!(
447 eye_color,
448 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr)]
449 #[repr(u32)]
450 pub enum EyeColor {
451 AmberOrange = 0,
452 AmberYellow = 1,
453 BrightBrown = 2,
454 CornflowerBlue = 3,
455 CuriousGreen = 4,
456 EmeraldGreen = 5,
457 ExoticPurple = 6,
458 FrozenBlue = 7,
459 GhastlyYellow = 8,
460 LoyalBrown = 9,
461 MagicPurple = 10,
462 NobleBlue = 11,
463 PineGreen = 12,
464 PumpkinOrange = 13,
465 RubyRed = 14,
466 RegalPurple = 15,
467 RustBrown = 16,
468 SapphireBlue = 17,
469 SulfurYellow = 18,
470 ToxicGreen = 19,
471 ViciousRed = 20,
472 VigorousBlack = 21,
473 }
474);
475
476make_case_elim!(
477 skin,
478 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr)]
479 #[repr(u32)]
480 pub enum Skin {
481 HumanOne = 0,
483 HumanTwo = 1,
484 HumanThree = 2,
485 HumanFour = 3,
486 HumanFive = 4,
487 HumanSix = 5,
488 HumanSeven = 6,
489 HumanEight = 7,
490 HumanNine = 8,
491 HumanTen = 9,
492 HumanEleven = 10,
493 HumanTwelve = 11,
494 HumanThirteen = 12,
495 HumanFourteen = 13,
496 HumanFifteen = 14,
497 HumanSixteen = 15,
498 HumanSeventeen = 16,
499 HumanEighteen = 17,
500 DwarfOne = 18,
502 DwarfTwo = 19,
503 DwarfThree = 20,
504 DwarfFour = 21,
505 DwarfFive = 22,
506 DwarfSix = 23,
507 DwarfSeven = 24,
508 DwarfEight = 25,
509 DwarfNine = 26,
510 DwarfTen = 27,
511 DwarfEleven = 28,
512 DwarfTwelve = 29,
513 DwarfThirteen = 30,
514 DwarfFourteen = 31,
515 ElfOne = 32,
517 ElfTwo = 33,
518 ElfThree = 34,
519 ElfFour = 35,
520 ElfFive = 36,
521 ElfSix = 37,
522 ElfSeven = 38,
523 ElfEight = 39,
524 ElfNine = 40,
525 ElfTen = 41,
526 ElfEleven = 42,
527 ElfTwelve = 43,
528 ElfThirteen = 44,
529 ElfFourteen = 45,
530 ElfFifteen = 46,
531 ElfSixteen = 47,
532 ElfSeventeen = 48,
533 ElfEighteen = 49,
534 OrcOne = 50,
536 OrcTwo = 51,
537 OrcThree = 52,
538 OrcFour = 53,
539 OrcFive = 54,
540 OrcSix = 55,
541 OrcSeven = 56,
542 OrcEight = 57,
543 DanariOne = 58,
545 DanariTwo = 59,
546 DanariThree = 60,
547 DanariFour = 61,
548 DanariFive = 62,
549 DanariSix = 63,
550 DanariSeven = 64,
551 DraugrOne = 65,
553 DraugrTwo = 66,
554 DraugrThree = 67,
555 DraugrFour = 68,
556 DraugrFive = 69,
557 DraugrSix = 70,
558 DraugrSeven = 71,
559 DraugrEight = 72,
560 DraugrNine = 73,
561 }
562);