veloren_voxygen_anim/quadruped_low/
mod.rs

1pub mod beta;
2pub mod breathe;
3pub mod combomelee;
4pub mod dash;
5pub mod idle;
6pub mod jump;
7pub mod leapshockwave;
8pub mod run;
9pub mod shockwave;
10pub mod shoot;
11pub mod spritesummon;
12pub mod stunned;
13pub mod tailwhip;
14
15// Reexports
16pub use self::{
17    beta::BetaAnimation, breathe::BreatheAnimation, combomelee::ComboAnimation,
18    dash::DashAnimation, idle::IdleAnimation, jump::JumpAnimation,
19    leapshockwave::LeapShockAnimation, run::RunAnimation, shockwave::ShockwaveAnimation,
20    shoot::ShootAnimation, spritesummon::SpriteSummonAnimation, stunned::StunnedAnimation,
21    tailwhip::TailwhipAnimation,
22};
23
24use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
25use common::{
26    comp::{self},
27    states::utils::StageSection,
28};
29use core::convert::TryFrom;
30
31pub type Body = comp::quadruped_low::Body;
32
33skeleton_impls!(struct QuadrupedLowSkeleton {
34    + head_c_upper,
35    + pub head_c_lower,
36    + jaw_c,
37    + head_l_upper,
38    + pub head_l_lower,
39    + jaw_l,
40    + head_r_upper,
41    + pub head_r_lower,
42    + jaw_r,
43    + chest,
44    + tail_front,
45    + tail_rear,
46    + foot_fl,
47    + foot_fr,
48    + foot_bl,
49    + foot_br,
50    mount,
51});
52
53impl Skeleton for QuadrupedLowSkeleton {
54    type Attr = SkeletonAttr;
55    type Body = Body;
56
57    const BONE_COUNT: usize = 16;
58    #[cfg(feature = "use-dyn-lib")]
59    const COMPUTE_FN: &'static [u8] = b"quadruped_low_compute_mats\0";
60
61    #[cfg_attr(
62        feature = "be-dyn-lib",
63        unsafe(export_name = "quadruped_low_compute_mats")
64    )]
65    fn compute_matrices_inner(
66        &self,
67        base_mat: Mat4<f32>,
68        buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
69        body: Self::Body,
70    ) -> Offsets {
71        let attr = SkeletonAttr::from(&body);
72        let base_mat = base_mat * Mat4::scaling_3d(attr.scaler / 11.0);
73
74        let chest_mat = base_mat * Mat4::<f32>::from(self.chest);
75        let tail_front = chest_mat * Mat4::<f32>::from(self.tail_front);
76        let tail_rear = tail_front * Mat4::<f32>::from(self.tail_rear);
77        let head_c_lower_mat = chest_mat * Mat4::<f32>::from(self.head_c_lower);
78        let head_c_upper_mat = head_c_lower_mat * Mat4::<f32>::from(self.head_c_upper);
79        let head_l_lower_mat = chest_mat * Mat4::<f32>::from(self.head_l_lower);
80        let head_l_upper_mat = head_l_lower_mat * Mat4::<f32>::from(self.head_l_upper);
81        let head_r_lower_mat = chest_mat * Mat4::<f32>::from(self.head_r_lower);
82        let head_r_upper_mat = head_r_lower_mat * Mat4::<f32>::from(self.head_r_upper);
83
84        *(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
85            make_bone(head_c_upper_mat),
86            make_bone(head_c_lower_mat),
87            make_bone(head_c_upper_mat * Mat4::<f32>::from(self.jaw_c)),
88            make_bone(head_l_upper_mat),
89            make_bone(head_l_lower_mat),
90            make_bone(head_l_upper_mat * Mat4::<f32>::from(self.jaw_l)),
91            make_bone(head_r_upper_mat),
92            make_bone(head_r_lower_mat),
93            make_bone(head_r_upper_mat * Mat4::<f32>::from(self.jaw_r)),
94            make_bone(chest_mat),
95            make_bone(tail_front),
96            make_bone(tail_rear),
97            make_bone(chest_mat * Mat4::<f32>::from(self.foot_fl)),
98            make_bone(chest_mat * Mat4::<f32>::from(self.foot_fr)),
99            make_bone(chest_mat * Mat4::<f32>::from(self.foot_bl)),
100            make_bone(chest_mat * Mat4::<f32>::from(self.foot_br)),
101        ];
102        //let (mount_bone_mat, mount_bone_ori) = (chest_mat, self.chest.orientation);
103        // Offset from the mounted bone's origin.
104        // Note: This could be its own bone if we need to animate it independently.
105
106        // NOTE: We apply the ori from base_mat externally so we don't need to worry
107        // about it here for now.
108
109        use comp::quadruped_low::Species::*;
110        let (mount_bone_mat, mount_bone_ori) = match (body.species, body.body_type) {
111            (Maneater, _) => (
112                head_c_upper_mat,
113                self.chest.orientation
114                    * self.head_c_lower.orientation
115                    * self.head_c_upper.orientation,
116            ),
117            _ => (chest_mat, self.chest.orientation),
118        };
119        let mount_position = (mount_bone_mat * Vec4::from_point(mount_point(&body)))
120            .homogenized()
121            .xyz();
122        let mount_orientation = mount_bone_ori;
123
124        Offsets {
125            viewpoint: Some((head_c_upper_mat * Vec4::new(0.0, 4.0, 1.0, 1.0)).xyz()),
126            mount_bone: Transform {
127                position: mount_position,
128                orientation: mount_orientation,
129                scale: Vec3::one(),
130            },
131            heads: vec![
132                (head_l_upper_mat * Vec4::unit_w()).xyz(),
133                (head_c_upper_mat * Vec4::unit_w()).xyz(),
134                (head_r_upper_mat * Vec4::unit_w()).xyz(),
135            ],
136            tail: Some((
137                (tail_front * Vec4::unit_w()).xyz(),
138                (tail_rear * Vec4::new(0.0, -attr.tail_rear_length, 0.0, 1.0)).xyz(),
139            )),
140            ..Default::default()
141        }
142    }
143}
144
145pub struct SkeletonAttr {
146    head_upper: (f32, f32),
147    head_lower: (f32, f32),
148    jaw: (f32, f32),
149    side_head_lower: (f32, f32, f32),
150    side_head_upper: (f32, f32, f32),
151    chest: (f32, f32),
152    tail_front: (f32, f32),
153    tail_rear: (f32, f32),
154    tail_rear_length: f32,
155    feet_f: (f32, f32, f32),
156    feet_b: (f32, f32, f32),
157    lean: (f32, f32),
158    scaler: f32,
159    tempo: f32,
160    tongue_for_tail: bool,
161}
162
163impl<'a> TryFrom<&'a comp::Body> for SkeletonAttr {
164    type Error = ();
165
166    fn try_from(body: &'a comp::Body) -> Result<Self, Self::Error> {
167        match body {
168            comp::Body::QuadrupedLow(body) => Ok(SkeletonAttr::from(body)),
169            _ => Err(()),
170        }
171    }
172}
173
174impl Default for SkeletonAttr {
175    fn default() -> Self {
176        Self {
177            head_upper: (0.0, 0.0),
178            head_lower: (0.0, 0.0),
179            jaw: (0.0, 0.0),
180            side_head_lower: (0.0, 0.0, 0.0),
181            side_head_upper: (0.0, 0.0, 0.0),
182            chest: (0.0, 0.0),
183            tail_front: (0.0, 0.0),
184            tail_rear: (0.0, 0.0),
185            tail_rear_length: 0.0,
186            feet_f: (0.0, 0.0, 0.0),
187            feet_b: (0.0, 0.0, 0.0),
188            lean: (0.0, 0.0),
189            scaler: 0.0,
190            tempo: 0.0,
191            tongue_for_tail: false,
192        }
193    }
194}
195
196impl<'a> From<&'a Body> for SkeletonAttr {
197    fn from(body: &'a Body) -> Self {
198        use comp::quadruped_low::Species::*;
199        Self {
200            head_upper: match (body.species, body.body_type) {
201                (Crocodile, _) => (1.5, 2.0),
202                (SeaCrocodile, _) => (1.5, 2.0),
203                (Alligator, _) => (0.5, 2.0),
204                (Salamander, _) => (0.5, 1.0),
205                (Elbst, _) => (0.5, 1.0),
206                (Monitor, _) => (5.5, 3.0),
207                (Asp, _) => (4.5, 10.5),
208                (Tortoise, _) => (5.0, 1.0),
209                (Rocksnapper, _) => (6.0, 0.5),
210                (Rootsnapper, _) => (6.0, 0.5),
211                (Reefsnapper, _) => (6.0, 0.5),
212                (Pangolin, _) => (-0.5, 8.0),
213                (Maneater, _) => (7.0, 11.5),
214                (Sandshark, _) => (8.5, 0.5),
215                (Hakulaq, _) => (8.0, 10.0),
216                (Dagon, _) => (8.0, 10.0),
217                (Lavadrake, _) => (7.0, 8.0),
218                (Icedrake, _) => (7.0, 8.0),
219                (Basilisk, _) => (5.0, 2.5),
220                (Deadwood, _) => (2.0, -3.0),
221                (Mossdrake, _) => (7.0, 8.0),
222                (Driggle, _) => (3.0, 4.0),
223                (Snaretongue, _) => (7.0, 5.5),
224                (Hydra, _) => (12.0, 19.0),
225            },
226            head_lower: match (body.species, body.body_type) {
227                (Crocodile, _) => (8.0, 0.0),
228                (SeaCrocodile, _) => (8.0, 0.0),
229                (Alligator, _) => (9.0, 0.25),
230                (Salamander, _) => (9.0, 0.0),
231                (Elbst, _) => (9.0, 0.0),
232                (Monitor, _) => (7.0, 0.0),
233                (Asp, _) => (6.0, -2.5),
234                (Tortoise, _) => (12.0, -3.5),
235                (Rocksnapper, _) => (12.0, -9.0),
236                (Rootsnapper, _) => (12.0, -9.0),
237                (Reefsnapper, _) => (12.0, -9.0),
238                (Pangolin, _) => (8.0, -9.0),
239                (Maneater, _) => (1.0, 4.5),
240                (Sandshark, _) => (13.5, -10.5),
241                (Hakulaq, _) => (10.5, 1.0),
242                (Dagon, _) => (12.0, -6.0),
243                (Lavadrake, _) => (9.0, -6.0),
244                (Icedrake, _) => (11.5, -6.0),
245                (Basilisk, _) => (12.5, -5.5),
246                (Deadwood, _) => (0.0, 0.0),
247                (Mossdrake, _) => (9.0, -6.0),
248                (Driggle, _) => (6.0, -3.0),
249                (Snaretongue, _) => (8.5, 0.0),
250                (Hydra, _) => (8.0, -6.5),
251            },
252            side_head_lower: match (body.species, body.body_type) {
253                (Hydra, _) => (9.0, 10.0, -6.5),
254                _ => (0.0, 0.0, 0.0),
255            },
256            side_head_upper: match (body.species, body.body_type) {
257                (Hydra, _) => ((1.0), (7.0), (17.0)),
258                _ => (0.0, 0.0, 0.0),
259            },
260            jaw: match (body.species, body.body_type) {
261                (Crocodile, _) => (2.5, -3.0),
262                (SeaCrocodile, _) => (2.5, -3.0),
263                (Alligator, _) => (2.5, -2.0),
264                (Salamander, _) => (0.5, -1.0),
265                (Elbst, _) => (0.5, -1.0),
266                (Monitor, _) => (3.0, -1.0),
267                (Asp, _) => (2.0, -2.0),
268                (Tortoise, _) => (-3.5, -2.0),
269                (Rocksnapper, _) => (-5.0, -1.5),
270                (Rootsnapper, _) => (-5.0, -1.5),
271                (Reefsnapper, _) => (-5.0, -1.5),
272                (Pangolin, _) => (0.0, 0.0),
273                (Maneater, _) => (-1.0, 4.0),
274                (Sandshark, _) => (-8.0, -5.5),
275                (Hakulaq, _) => (-6.5, -4.0),
276                (Dagon, _) => (2.0, -2.0),
277                (Lavadrake, _) => (3.0, -5.0),
278                (Icedrake, _) => (-0.5, -8.0),
279                (Basilisk, _) => (0.5, -3.0),
280                (Deadwood, _) => (-1.0, 4.0),
281                (Mossdrake, _) => (3.0, -5.0),
282                (Driggle, _) => (-2.0, -5.0),
283                (Snaretongue, _) => (-7.0, -7.0),
284                (Hydra, _) => (1.0, -2.0),
285            },
286            chest: match (body.species, body.body_type) {
287                (Crocodile, _) => (0.0, 5.0),
288                (SeaCrocodile, _) => (0.0, 5.0),
289                (Alligator, _) => (0.0, 5.0),
290                (Salamander, _) => (0.0, 5.0),
291                (Elbst, _) => (0.0, 5.0),
292                (Monitor, _) => (0.0, 5.0),
293                (Asp, _) => (0.0, 8.0),
294                (Tortoise, _) => (0.0, 11.0),
295                (Rocksnapper, _) => (0.0, 18.5),
296                (Rootsnapper, _) => (0.0, 18.5),
297                (Reefsnapper, _) => (0.0, 18.5),
298                (Pangolin, _) => (0.0, 7.0),
299                (Maneater, _) => (0.0, 12.0),
300                (Sandshark, _) => (0.0, 20.0),
301                (Hakulaq, _) => (0.0, 13.5),
302                (Dagon, _) => (0.0, 13.5),
303                (Lavadrake, _) => (0.0, 16.5),
304                (Icedrake, _) => (0.0, 16.5),
305                (Basilisk, _) => (0.0, 15.0),
306                (Deadwood, _) => (0.0, 12.0),
307                (Mossdrake, _) => (0.0, 16.5),
308                (Driggle, _) => (0.0, 8.0),
309                (Snaretongue, _) => (-8.0, 9.0),
310                (Hydra, _) => (0.0, 16.0),
311            },
312            tail_rear: match (body.species, body.body_type) {
313                (Crocodile, _) => (-12.5, -1.0),
314                (SeaCrocodile, _) => (-12.5, -1.0),
315                (Alligator, _) => (-13.0, -1.0),
316                (Salamander, _) => (-6.5, 0.0),
317                (Elbst, _) => (-6.5, 0.0),
318                (Monitor, _) => (-12.0, 0.0),
319                (Asp, _) => (-14.0, -2.0),
320                (Tortoise, _) => (-10.0, -1.5),
321                (Rocksnapper, _) => (-14.5, -2.0),
322                (Rootsnapper, _) => (-14.5, -2.0),
323                (Reefsnapper, _) => (-14.5, -2.0),
324                (Pangolin, _) => (-7.0, -3.0),
325                (Maneater, _) => (-15.0, 4.0),
326                (Sandshark, _) => (-10.0, 0.5),
327                (Hakulaq, _) => (-9.0, -2.0),
328                (Dagon, _) => (-9.0, -2.0),
329                (Lavadrake, _) => (-12.0, -2.0),
330                (Icedrake, _) => (-12.0, 1.0),
331                (Basilisk, _) => (-10.0, -4.0),
332                (Deadwood, _) => (-15.0, 4.0),
333                (Mossdrake, _) => (-12.0, -2.0),
334                (Driggle, _) => (-4.0, 0.0),
335                (Snaretongue, _) => (5.0, 0.0),
336                (Hydra, _) => (-16.0, -1.0),
337            },
338            tail_rear_length: match (body.species, body.body_type) {
339                // TODO: Tweak tails as needed
340                (Crocodile, _) => 1.0,
341                (SeaCrocodile, _) => 1.0,
342                (Alligator, _) => 1.0,
343                (Salamander, _) => 1.0,
344                (Elbst, _) => 1.0,
345                (Monitor, _) => 1.0,
346                (Asp, _) => 1.0,
347                (Tortoise, _) => 1.0,
348                (Rocksnapper, _) => 1.0,
349                (Rootsnapper, _) => 1.0,
350                (Reefsnapper, _) => 1.0,
351                (Pangolin, _) => 1.0,
352                (Maneater, _) => 1.0,
353                (Sandshark, _) => 1.0,
354                (Hakulaq, _) => 1.0,
355                (Dagon, _) => 1.0,
356                (Lavadrake, _) => 1.0,
357                (Icedrake, _) => 1.0,
358                (Basilisk, _) => 1.0,
359                (Deadwood, _) => 1.0,
360                (Mossdrake, _) => 1.0,
361                (Driggle, _) => 1.0,
362                (Snaretongue, _) => 1.0,
363                (Hydra, _) => 10.0,
364            },
365            tail_front: match (body.species, body.body_type) {
366                (Crocodile, _) => (-6.0, 0.0),
367                (SeaCrocodile, _) => (-6.0, 0.0),
368                (Alligator, _) => (-5.0, 0.0),
369                (Salamander, _) => (-7.5, 0.0),
370                (Elbst, _) => (-7.0, 0.0),
371                (Monitor, _) => (-6.5, 0.0),
372                (Asp, _) => (-6.0, -2.0),
373                (Tortoise, _) => (-13.0, -3.5),
374                (Rocksnapper, _) => (-13.5, -6.5),
375                (Rootsnapper, _) => (-13.5, -6.5),
376                (Reefsnapper, _) => (-13.5, -6.5),
377                (Pangolin, _) => (-7.5, -0.5),
378                (Maneater, _) => (-1.0, 4.0),
379                (Sandshark, _) => (-13.0, -8.0),
380                (Hakulaq, _) => (-6.0, -5.5),
381                (Dagon, _) => (-9.0, -2.0),
382                (Lavadrake, _) => (-7.0, -4.5),
383                (Icedrake, _) => (-7.0, -4.5),
384                (Basilisk, _) => (-6.5, -5.5),
385                (Deadwood, _) => (-1.0, 4.0),
386                (Mossdrake, _) => (-7.0, -4.5),
387                (Driggle, _) => (-5.5, -4.0),
388                (Snaretongue, _) => (5.0, -2.0),
389                (Hydra, _) => (-14.0, -7.5),
390            },
391            feet_f: match (body.species, body.body_type) {
392                (Crocodile, _) => (3.5, 6.0, -1.0),
393                (SeaCrocodile, _) => (3.5, 6.0, -1.0),
394                (Alligator, _) => (4.5, 4.25, -1.0),
395                (Salamander, _) => (5.0, 4.5, -2.0),
396                (Elbst, _) => (5.0, 4.5, -2.0),
397                (Monitor, _) => (3.0, 5.0, 0.0),
398                (Asp, _) => (1.5, 4.0, -1.0),
399                (Tortoise, _) => (5.5, 6.5, -3.0),
400                (Rocksnapper, _) => (7.5, 5.0, -8.5),
401                (Rootsnapper, _) => (7.5, 5.0, -8.5),
402                (Reefsnapper, _) => (7.5, 5.0, -8.5),
403                (Pangolin, _) => (5.5, 5.5, -1.0),
404                (Maneater, _) => (4.5, 4.0, -5.5),
405                (Sandshark, _) => (5.5, 2.0, -8.0),
406                (Hakulaq, _) => (4.5, 2.0, -4.5),
407                (Dagon, _) => (4.5, 2.0, -4.5),
408                (Lavadrake, _) => (4.5, 4.0, -6.5),
409                (Icedrake, _) => (4.5, 4.0, -6.5),
410                (Basilisk, _) => (6.5, 4.0, -2.0),
411                (Deadwood, _) => (3.5, 4.0, -5.0),
412                (Mossdrake, _) => (4.5, 4.0, -6.5),
413                (Driggle, _) => (4.5, 2.5, -4.0),
414                (Snaretongue, _) => (6.5, 6.5, 1.0),
415                (Hydra, _) => (13.0, 7.0, -3.0),
416            },
417            feet_b: match (body.species, body.body_type) {
418                (Crocodile, _) => (3.5, -6.0, -1.0),
419                (SeaCrocodile, _) => (3.5, -6.0, -1.0),
420                (Alligator, _) => (4.5, -5.5, -1.0),
421                (Salamander, _) => (3.0, -6.0, -2.0),
422                (Elbst, _) => (3.0, -6.0, -2.0),
423                (Monitor, _) => (2.5, -6.5, 0.0),
424                (Asp, _) => (2.5, -5.5, -1.0),
425                (Tortoise, _) => (5.5, -11.5, -3.0),
426                (Rocksnapper, _) => (8.0, -12.0, -9.5),
427                (Rootsnapper, _) => (8.0, -12.0, -9.5),
428                (Reefsnapper, _) => (8.0, -12.0, -9.5),
429                (Pangolin, _) => (6.5, -3.5, -1.0),
430                (Maneater, _) => (4.5, -2.5, -3.0),
431                (Sandshark, _) => (3.5, -15.0, -14.0),
432                (Hakulaq, _) => (3.5, -8.0, -4.5),
433                (Dagon, _) => (3.5, -8.0, -4.5),
434                (Lavadrake, _) => (3.5, -8.0, -6.5),
435                (Icedrake, _) => (3.5, -8.0, -6.5),
436                (Basilisk, _) => (5.5, -6.5, -2.0),
437                (Deadwood, _) => (3.5, -6.0, -5.0),
438                (Mossdrake, _) => (3.5, -8.0, -6.5),
439                (Driggle, _) => (3.5, -3.5, -5.0),
440                (Snaretongue, _) => (1.5, 1.5, 2.0),
441                (Hydra, _) => (5.0, -6.5, -5.0),
442            },
443            lean: match (body.species, body.body_type) {
444                (Pangolin, _) => (0.4, 0.0),
445                _ => (0.0, 1.0),
446            },
447            scaler: match (body.species, body.body_type) {
448                (Crocodile, _) => 1.05,
449                (SeaCrocodile, _) => 1.05,
450                (Alligator, _) => 1.12,
451                (Salamander, _) => 1.12,
452                (Elbst, _) => 1.12,
453                (Monitor, _) => 0.9,
454                (Asp, _) => 1.12,
455                (Rocksnapper, _) => 1.12,
456                (Rootsnapper, _) => 1.12,
457                (Reefsnapper, _) => 1.12,
458                (Hakulaq, _) => 1.05,
459                (Dagon, _) => 1.05,
460                (Pangolin, _) => 1.05,
461                (Maneater, _) => 1.12,
462                (Lavadrake, _) => 1.12,
463                (Icedrake, _) => 1.12,
464                (Basilisk, _) => 1.3,
465                (Mossdrake, _) => 1.12,
466                (Snaretongue, _) => 1.0,
467                (Hydra, _) => 1.5,
468                _ => 0.9,
469            },
470            tempo: match (body.species, body.body_type) {
471                (Crocodile, _) => 0.7,
472                (SeaCrocodile, _) => 0.7,
473                (Alligator, _) => 0.7,
474                (Salamander, _) => 0.85,
475                (Elbst, _) => 0.85,
476                (Monitor, _) => 1.4,
477                (Tortoise, _) => 0.7,
478                (Rocksnapper, _) => 0.7,
479                (Rootsnapper, _) => 0.7,
480                (Reefsnapper, _) => 0.7,
481                (Hakulaq, _) => 1.2,
482                (Dagon, _) => 1.2,
483                (Pangolin, _) => 1.15,
484                (Maneater, _) => 0.9,
485                (Lavadrake, _) => 1.1,
486                (Icedrake, _) => 1.1,
487                (Basilisk, _) => 0.8,
488                (Mossdrake, _) => 1.1,
489                (Snaretongue, _) => 0.7,
490                (Hydra, _) => 0.6,
491                _ => 1.0,
492            },
493            // bool to special case Snaretongue
494            tongue_for_tail: matches!(body.species, Snaretongue),
495        }
496    }
497}
498fn mount_point(body: &Body) -> Vec3<f32> {
499    use comp::quadruped_low::Species::*;
500    match (body.species, body.body_type) {
501        (Crocodile, _) => (0.0, 3.5, 3.5),
502        (Alligator, _) => (0.0, 2.5, 3.0),
503        (Salamander, _) => (0.0, 2.0, 4.0),
504        (Monitor, _) => (0.0, 0.0, 3.0),
505        (Asp, _) => (0.0, 2.0, 4.0),
506        (Tortoise, _) => (0.0, 0.0, 6.0),
507        (Pangolin, _) => (0.0, -1.0, 4.5),
508        (Maneater, _) => (0.0, 4.0, -7.5),
509        (Sandshark, _) => (0.0, -6.0, 0.0),
510        (Hakulaq, _) => (0.0, 5.0, 2.5),
511        (Lavadrake, _) => (0.0, 2.0, -0.5),
512        (Basilisk, _) => (0.0, -1.5, 8.0),
513        (Deadwood, _) => (0.0, -2.0, 3.0),
514        (Icedrake, _) => (0.0, -7.0, 6.0),
515        (SeaCrocodile, _) => (1.0, 3.5, 6.0),
516        (Dagon, _) => (1.0, 9.5, 0.5),
517        (Rocksnapper, _) => (0.0, 7.0, 8.5),
518        (Rootsnapper, _) => (0.0, -2.0, 12.5),
519        (Reefsnapper, _) => (0.0, 2.0, 4.5),
520        (Elbst, _) => (0.0, 2.0, 3.0),
521        (Mossdrake, _) => (0.0, 2.0, 3.5),
522        (Driggle, _) => (0.0, 6.0, 2.0),
523        (Snaretongue, _) => (0.0, 2.0, 6.0),
524        (Hydra, _) => (0.0, 2.0, 4.0),
525    }
526    .into()
527}
528
529pub fn quadruped_low_alpha(
530    next: &mut QuadrupedLowSkeleton,
531    _s_a: &SkeletonAttr,
532    stage_section: StageSection,
533    anim_time: f32,
534    global_time: f32,
535    timer: f32,
536) {
537    let (movement1base, movement2base, movement3) = match stage_section {
538        StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0),
539        StageSection::Action => (1.0, anim_time.powi(4), 0.0),
540        StageSection::Recover => (1.0, 1.0, anim_time),
541        _ => (0.0, 0.0, 0.0),
542    };
543    let pullback = 1.0 - movement3;
544    let subtract = global_time - timer;
545    let check = subtract - subtract.trunc();
546    let mirror = (check - 0.5).signum();
547    let twitch3 = (mirror * movement3 * 9.0).sin();
548    let movement1 = mirror * movement1base * pullback;
549    let movement2 = mirror * movement2base * pullback;
550    let movement1abs = movement1base * pullback;
551    let movement2abs = movement2base * pullback;
552
553    // Center head
554    next.head_c_upper.orientation = Quaternion::rotation_z(twitch3 * -0.7);
555
556    next.head_c_lower.orientation =
557        Quaternion::rotation_x(movement1abs * 0.35 + movement2abs * -0.9)
558            * Quaternion::rotation_y(movement1 * 0.7 + movement2 * -1.0);
559
560    next.jaw_c.orientation = Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * 0.5);
561
562    // Left head
563    next.head_l_upper.orientation = Quaternion::rotation_z(twitch3 * -0.7);
564
565    next.head_l_lower.orientation =
566        Quaternion::rotation_x(movement1abs * 0.35 + movement2abs * -0.9)
567            * Quaternion::rotation_y(movement1 * 0.7 + movement2 * -1.0);
568
569    next.jaw_l.orientation = Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * 0.5);
570
571    // Right head
572    next.head_r_upper.orientation = Quaternion::rotation_z(twitch3 * -0.7);
573
574    next.head_r_lower.orientation =
575        Quaternion::rotation_x(movement1abs * 0.35 + movement2abs * -0.9)
576            * Quaternion::rotation_y(movement1 * 0.7 + movement2 * -1.0);
577
578    next.jaw_r.orientation = Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * 0.5);
579
580    next.chest.orientation = Quaternion::rotation_y(movement1 * -0.08 + movement2 * 0.15)
581        * Quaternion::rotation_z(movement1 * -0.2 + movement2 * 0.6);
582
583    next.tail_front.orientation =
584        Quaternion::rotation_x(0.15) * Quaternion::rotation_z(movement1 * -0.4 + movement2 * -0.2);
585
586    next.tail_rear.orientation =
587        Quaternion::rotation_x(-0.12) * Quaternion::rotation_z(movement1 * -0.4 + movement2 * -0.2);
588}
589
590pub fn quadruped_low_beta(
591    next: &mut QuadrupedLowSkeleton,
592    _s_a: &SkeletonAttr,
593    stage_section: StageSection,
594    anim_time: f32,
595    global_time: f32,
596    timer: f32,
597) {
598    let (movement1base, movement2base, movement3) = match stage_section {
599        StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0),
600        StageSection::Action => (1.0, anim_time.powi(4), 0.0),
601        StageSection::Recover => (1.0, 1.0, anim_time),
602        _ => (0.0, 0.0, 0.0),
603    };
604    let pullback = 1.0 - movement3;
605    let subtract = global_time - timer;
606    let check = subtract - subtract.trunc();
607    let mirror = (check - 0.5).signum();
608    let twitch3 = (mirror * movement3 * 9.0).sin();
609    let movement1 = mirror * movement1base * pullback;
610    let movement2 = mirror * movement2base * pullback;
611    let movement1abs = movement1base * pullback;
612    let movement2abs = movement2base * pullback;
613
614    // Center head
615    next.head_c_upper.orientation = Quaternion::rotation_z(twitch3 * 0.2);
616
617    next.head_c_lower.orientation =
618        Quaternion::rotation_x(movement1abs * 0.15 + movement2abs * -0.6)
619            * Quaternion::rotation_y(movement1 * -0.1 + movement2 * 0.15);
620
621    next.jaw_c.orientation = Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.9);
622
623    // Left head
624    next.head_l_upper.orientation = Quaternion::rotation_z(twitch3 * 0.2);
625
626    next.head_l_lower.orientation =
627        Quaternion::rotation_x(movement1abs * 0.15 + movement2abs * -0.6)
628            * Quaternion::rotation_y(movement1 * -0.1 + movement2 * 0.15);
629
630    next.jaw_l.orientation = Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.9);
631
632    // Right head
633    next.head_r_upper.orientation = Quaternion::rotation_z(twitch3 * 0.2);
634
635    next.head_r_lower.orientation =
636        Quaternion::rotation_x(movement1abs * 0.15 + movement2abs * -0.6)
637            * Quaternion::rotation_y(movement1 * -0.1 + movement2 * 0.15);
638
639    next.jaw_r.orientation = Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.9);
640
641    next.chest.orientation = Quaternion::rotation_y(movement1 * 0.08 + movement2 * -0.15)
642        * Quaternion::rotation_z(movement1 * 0.2 + movement2 * -0.3);
643
644    next.tail_front.orientation =
645        Quaternion::rotation_x(0.15) * Quaternion::rotation_z(movement1 * 0.4 + movement2 * 0.2);
646
647    next.tail_rear.orientation =
648        Quaternion::rotation_x(-0.12) * Quaternion::rotation_z(movement1 * 0.4 + movement2 * 0.2);
649}