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), }
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#[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
150pub 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
238pub 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 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 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 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 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 OrcOne = 50,
516 OrcTwo = 51,
517 OrcThree = 52,
518 OrcFour = 53,
519 OrcFive = 54,
520 OrcSix = 55,
521 OrcSeven = 56,
522 OrcEight = 57,
523 DanariOne = 58,
525 DanariTwo = 59,
526 DanariThree = 60,
527 DanariFour = 61,
528 DanariFive = 62,
529 DanariSix = 63,
530 DanariSeven = 64,
531 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);