1use crate::{make_case_elim, make_proj_elim};
2use common_i18n::Content;
3use rand::{seq::SliceRandom, thread_rng};
4use serde::{Deserialize, Serialize};
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 }
13);
14
15impl Body {
16 pub fn random() -> Self {
17 let mut rng = thread_rng();
18 let species = *ALL_SPECIES.choose(&mut rng).unwrap();
19 Self::random_with(&mut rng, &species)
20 }
21
22 #[inline]
23 pub fn random_with(rng: &mut impl rand::Rng, &species: &Species) -> Self {
24 let body_type = *ALL_BODY_TYPES.choose(rng).unwrap();
25 Self { species, body_type }
26 }
27
28 pub fn localize_npc(&self) -> Option<Content> {
33 let key = match &self.species {
34 Species::Ogre => match self.body_type {
35 BodyType::Male => "body-npc-speech-biped_large-ogre-male",
36 BodyType::Female => "body-npc-speech-biped_large-ogre-female",
37 },
38 Species::Cyclops => "body-npc-speech-biped_large-cyclops",
39 Species::Wendigo => "body-npc-speech-biped_large-wendigo",
40 Species::Werewolf => "body-npc-speech-biped_large-werewolf",
41 Species::Cavetroll => "body-npc-speech-biped_large-cave_troll",
42 Species::Mountaintroll => "body-npc-speech-biped_large-mountain_troll",
43 Species::Swamptroll => "body-npc-speech-biped_large-swamp_troll",
44 Species::Blueoni => "body-npc-speech-biped_large-blue_oni",
45 Species::Redoni => "body-npc-speech-biped_large-red_oni",
46 Species::Tursus => "body-npc-speech-biped_large-tursus",
47 Species::Dullahan => "body-npc-speech-biped_large-dullahan",
48 Species::Occultsaurok => "body-npc-speech-biped_large-occult_saurok",
49 Species::Mightysaurok => "body-npc-speech-biped_large-mighty_saurok",
50 Species::Slysaurok => "body-npc-speech-biped_large-sly_saurok",
51 Species::Mindflayer => "body-npc-speech-biped_large-mindflayer",
52 Species::Minotaur => "body-npc-speech-biped_large-minotaur",
53 Species::Tidalwarrior => "body-npc-speech-biped_large-tidal_warrior",
54 Species::Yeti => "body-npc-speech-biped_large-yeti",
55 Species::Harvester => "body-npc-speech-biped_large-harvester",
56 Species::Cultistwarlord => "body-npc-speech-biped_large-cultist_warlord",
57 Species::Cultistwarlock => "body-npc-speech-biped_large-cultist_warlock",
58 Species::Huskbrute => "body-npc-speech-biped_large-husk_brute",
59 Species::Gigasfrost => "body-npc-speech-biped_large-gigas_frost",
60 Species::AdletElder => "body-npc-speech-biped_large-adlet_elder",
61 Species::SeaBishop => "body-npc-speech-biped_large-sea_bishop",
62 Species::HaniwaGeneral => "body-npc-speech-biped_large-haniwa_general",
63 Species::TerracottaBesieger => "body-npc-speech-biped_large-terracotta_besieger",
64 Species::TerracottaDemolisher => "body-npc-speech-biped_large-terracotta_demolisher",
65 Species::TerracottaPunisher => "body-npc-speech-biped_large-terracotta_punisher",
66 Species::TerracottaPursuer => "body-npc-speech-biped_large-terracotta_pursuer",
67 Species::Cursekeeper => "body-npc-speech-biped_large-cursekeeper",
68 Species::Forgemaster => "body-npc-speech-biped_large-forgemaster",
69 Species::Strigoi => "body-npc-speech-biped_large-strigoi",
70 Species::Executioner => "body-npc-speech-biped_large-executioner",
71 };
72
73 Some(Content::localized(key))
74 }
75}
76
77impl From<Body> for super::Body {
78 fn from(body: Body) -> Self { super::Body::BipedLarge(body) }
79}
80
81make_case_elim!(
82 species,
83 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
84 #[repr(u32)]
85 pub enum Species {
86 Ogre = 0,
87 Cyclops = 1,
88 Wendigo = 2,
89 Cavetroll = 3,
90 Mountaintroll = 4,
91 Swamptroll = 5,
92 Dullahan = 6,
93 Werewolf = 7,
94 Occultsaurok = 8,
95 Mightysaurok = 9,
96 Slysaurok = 10,
97 Mindflayer = 11,
98 Minotaur = 12,
99 Tidalwarrior = 13,
100 Yeti = 14,
101 Harvester = 15,
102 Blueoni = 16,
103 Redoni = 17,
104 Cultistwarlord = 18,
105 Cultistwarlock = 19,
106 Huskbrute = 20,
107 Tursus = 21,
108 Gigasfrost = 22,
109 AdletElder = 23,
110 SeaBishop = 24,
111 HaniwaGeneral = 25,
112 TerracottaBesieger = 26,
113 TerracottaDemolisher = 27,
114 TerracottaPunisher = 28,
115 TerracottaPursuer = 29,
116 Cursekeeper = 30,
117 Forgemaster = 31,
118 Strigoi = 32,
119 Executioner = 33,
120 }
121);
122
123#[derive(Clone, Debug, Deserialize)]
127pub struct AllSpecies<SpeciesMeta> {
128 pub ogre: SpeciesMeta,
129 pub cyclops: SpeciesMeta,
130 pub wendigo: SpeciesMeta,
131 pub troll_cave: SpeciesMeta,
132 pub troll_mountain: SpeciesMeta,
133 pub troll_swamp: SpeciesMeta,
134 pub dullahan: SpeciesMeta,
135 pub werewolf: SpeciesMeta,
136 pub saurok_occult: SpeciesMeta,
137 pub saurok_mighty: SpeciesMeta,
138 pub saurok_sly: SpeciesMeta,
139 pub mindflayer: SpeciesMeta,
140 pub minotaur: SpeciesMeta,
141 pub tidalwarrior: SpeciesMeta,
142 pub yeti: SpeciesMeta,
143 pub harvester: SpeciesMeta,
144 pub oni_blue: SpeciesMeta,
145 pub oni_red: SpeciesMeta,
146 pub cultist_warlord: SpeciesMeta,
147 pub cultist_warlock: SpeciesMeta,
148 pub husk_brute: SpeciesMeta,
149 pub tursus: SpeciesMeta,
150 pub gigas_frost: SpeciesMeta,
151 pub adlet_elder: SpeciesMeta,
152 pub sea_bishop: SpeciesMeta,
153 pub haniwa_general: SpeciesMeta,
154 pub terracotta_besieger: SpeciesMeta,
155 pub terracotta_demolisher: SpeciesMeta,
156 pub terracotta_punisher: SpeciesMeta,
157 pub terracotta_pursuer: SpeciesMeta,
158 pub cursekeeper: SpeciesMeta,
159 pub forgemaster: SpeciesMeta,
160 pub strigoi: SpeciesMeta,
161 pub executioner: SpeciesMeta,
162}
163
164impl<'a, SpeciesMeta> core::ops::Index<&'a Species> for AllSpecies<SpeciesMeta> {
165 type Output = SpeciesMeta;
166
167 #[inline]
168 fn index(&self, &index: &'a Species) -> &Self::Output {
169 match index {
170 Species::Ogre => &self.ogre,
171 Species::Cyclops => &self.cyclops,
172 Species::Wendigo => &self.wendigo,
173 Species::Cavetroll => &self.troll_cave,
174 Species::Mountaintroll => &self.troll_mountain,
175 Species::Swamptroll => &self.troll_swamp,
176 Species::Dullahan => &self.dullahan,
177 Species::Werewolf => &self.werewolf,
178 Species::Occultsaurok => &self.saurok_occult,
179 Species::Mightysaurok => &self.saurok_mighty,
180 Species::Slysaurok => &self.saurok_sly,
181 Species::Mindflayer => &self.mindflayer,
182 Species::Minotaur => &self.minotaur,
183 Species::Tidalwarrior => &self.tidalwarrior,
184 Species::Yeti => &self.yeti,
185 Species::Harvester => &self.harvester,
186 Species::Blueoni => &self.oni_blue,
187 Species::Redoni => &self.oni_red,
188 Species::Cultistwarlord => &self.cultist_warlord,
189 Species::Cultistwarlock => &self.cultist_warlock,
190 Species::Huskbrute => &self.husk_brute,
191 Species::Tursus => &self.tursus,
192 Species::Gigasfrost => &self.gigas_frost,
193 Species::AdletElder => &self.adlet_elder,
194 Species::SeaBishop => &self.sea_bishop,
195 Species::HaniwaGeneral => &self.haniwa_general,
196 Species::TerracottaBesieger => &self.terracotta_besieger,
197 Species::TerracottaDemolisher => &self.terracotta_demolisher,
198 Species::TerracottaPunisher => &self.terracotta_punisher,
199 Species::TerracottaPursuer => &self.terracotta_pursuer,
200 Species::Cursekeeper => &self.cursekeeper,
201 Species::Forgemaster => &self.forgemaster,
202 Species::Strigoi => &self.strigoi,
203 Species::Executioner => &self.executioner,
204 }
205 }
206}
207
208pub const ALL_SPECIES: [Species; 34] = [
209 Species::Ogre,
210 Species::Cyclops,
211 Species::Wendigo,
212 Species::Cavetroll,
213 Species::Mountaintroll,
214 Species::Swamptroll,
215 Species::Dullahan,
216 Species::Werewolf,
217 Species::Occultsaurok,
218 Species::Mightysaurok,
219 Species::Slysaurok,
220 Species::Mindflayer,
221 Species::Minotaur,
222 Species::Tidalwarrior,
223 Species::Yeti,
224 Species::Harvester,
225 Species::Blueoni,
226 Species::Redoni,
227 Species::Cultistwarlord,
228 Species::Cultistwarlock,
229 Species::Huskbrute,
230 Species::Tursus,
231 Species::Gigasfrost,
232 Species::AdletElder,
233 Species::SeaBishop,
234 Species::HaniwaGeneral,
235 Species::TerracottaBesieger,
236 Species::TerracottaDemolisher,
237 Species::TerracottaPunisher,
238 Species::TerracottaPursuer,
239 Species::Cursekeeper,
240 Species::Forgemaster,
241 Species::Strigoi,
242 Species::Executioner,
243];
244
245impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
246 type IntoIter = std::iter::Copied<std::slice::Iter<'static, Self::Item>>;
247 type Item = Species;
248
249 fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() }
250}
251
252make_case_elim!(
253 body_type,
254 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
255 #[repr(u32)]
256 pub enum BodyType {
257 Female = 0,
258 Male = 1,
259 }
260);
261pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male];