Skip to main content

veloren_voxygen_anim/character/
mod.rs

1pub mod basic;
2pub mod boost;
3pub mod climb;
4pub mod collect;
5pub mod consume;
6pub mod crawl;
7pub mod dance;
8pub mod equip;
9pub mod glidewield;
10pub mod gliding;
11pub mod idle;
12pub mod jump;
13pub mod mount;
14pub mod multi;
15pub mod music;
16pub mod pet;
17pub mod roll;
18pub mod run;
19pub mod sit;
20pub mod sleep;
21pub mod sneak;
22pub mod sneakequip;
23pub mod sneakwield;
24pub mod staggered;
25pub mod stand;
26pub mod steer;
27pub mod stunned;
28pub mod swim;
29pub mod swimwield;
30pub mod talk;
31pub mod throw;
32pub mod wallrun;
33pub mod wield;
34
35// Reexports
36pub use self::{
37    basic::{BasicAction, BasicActionDependency},
38    boost::BoostAnimation,
39    climb::ClimbAnimation,
40    collect::CollectAnimation,
41    consume::ConsumeAnimation,
42    crawl::CrawlAnimation,
43    dance::DanceAnimation,
44    equip::EquipAnimation,
45    glidewield::GlideWieldAnimation,
46    gliding::GlidingAnimation,
47    idle::IdleAnimation,
48    jump::JumpAnimation,
49    mount::MountAnimation,
50    multi::{MultiAction, MultiActionDependency},
51    music::MusicAnimation,
52    pet::PetAnimation,
53    roll::RollAnimation,
54    run::RunAnimation,
55    sit::SitAnimation,
56    sleep::SleepAnimation,
57    sneak::SneakAnimation,
58    sneakequip::SneakEquipAnimation,
59    sneakwield::SneakWieldAnimation,
60    staggered::StaggeredAnimation,
61    stand::StandAnimation,
62    steer::SteerAnimation,
63    stunned::StunnedAnimation,
64    swim::SwimAnimation,
65    swimwield::SwimWieldAnimation,
66    talk::TalkAnimation,
67    throw::ThrowAnimation,
68    wallrun::WallrunAnimation,
69    wield::WieldAnimation,
70};
71use super::{FigureBoneData, Skeleton, vek::*};
72use common::comp::{
73    self,
74    tool::{Hands, ToolKind},
75};
76use core::{convert::TryFrom, f32::consts::PI};
77
78pub type Body = comp::humanoid::Body;
79
80skeleton_impls!(struct CharacterSkeleton ComputedCharacterSkeleton {
81    + head
82    + chest
83    + belt
84    + back
85    + shorts
86    + hand_l
87    + hand_r
88    + foot_l
89    + foot_r
90    + shoulder_l
91    + shoulder_r
92    + glider
93    + main
94    + second
95    + lantern
96    + hold
97    torso
98    control
99    control_l
100    control_r
101    :: // Begin non-bone fields
102    holding_lantern: bool,
103    // The offset from the back that carried weapons should be given to avoid clipping due to, say, a backpack
104    back_carry_offset: f32,
105    main_weapon_trail: bool,
106    off_weapon_trail: bool,
107    // Cannot exist at same time as weapon trails. Since gliding and attacking are mutually exclusive, should never be a concern.
108    glider_trails: bool,
109    squash: f32,
110});
111
112impl CharacterSkeleton {
113    pub fn new(holding_lantern: bool, back_carry_offset: f32, squash: f32) -> Self {
114        Self {
115            holding_lantern,
116            back_carry_offset,
117            squash,
118            ..Self::default()
119        }
120    }
121}
122
123impl Skeleton for CharacterSkeleton {
124    type Attr = SkeletonAttr;
125    type Body = Body;
126    type ComputedSkeleton = ComputedCharacterSkeleton;
127
128    const BONE_COUNT: usize = ComputedCharacterSkeleton::BONE_COUNT;
129    #[cfg(feature = "use-dyn-lib")]
130    const COMPUTE_FN: &'static [u8] = b"character_compute_mats\0";
131
132    #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "character_compute_mats"))]
133    fn compute_matrices_inner(
134        &self,
135        base_mat: Mat4<f32>,
136        buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
137        body: Self::Body,
138    ) -> Self::ComputedSkeleton {
139        let height_scale = body.height_scale();
140
141        // TODO: extract scaler from body to it's own method so we can call that
142        // directly instead of going through SkeletonAttr? (note todo also
143        // appiles to other body variant animations)
144        let base_mat =
145            base_mat * Mat4::scaling_3d(Body::BASE_HEIGHT * body.scaler() * (1.0 / 25.0));
146
147        let transform_chest = |tr: Transform<f32, f32, f32>| Transform {
148            position: tr.position * Vec3::new(1.0, 1.0, self.squash * height_scale.powi(2))
149                + Vec3::new(0.0, (self.squash - 1.0).min(0.0) * 8.0, 0.0),
150            orientation: tr.orientation
151                * Quaternion::rotation_x((self.squash - 1.0).min(0.0) * 2.0),
152            scale: tr.scale * Lerp::lerp(1.0, height_scale, 0.25),
153        };
154        let transform_limb = |tr: Transform<f32, f32, f32>| Transform {
155            position: tr.position * Vec3::new(1.0, 1.0, self.squash)
156                + Vec3::new(0.0, (1.0 - self.squash).max(0.0) * 5.0, 0.0),
157            orientation: tr.orientation
158                * Quaternion::rotation_x((1.0 - self.squash).max(0.0) * 2.0),
159            ..tr
160        };
161        let transform_other = |stretch: f32, tr: Transform<f32, f32, f32>| Transform {
162            position: tr.position * Vec3::new(1.0, 1.0, height_scale.max(0.0).powf(stretch * 2.0)),
163            scale: tr.scale * Vec3::new(1.0, 1.0, height_scale.max(1.0).powf(stretch * 2.0)),
164            ..tr
165        };
166
167        let torso_mat = base_mat * Mat4::<f32>::from(self.torso);
168        let chest_mat = torso_mat * Mat4::<f32>::from(transform_chest(self.chest));
169        let head_mat = chest_mat * Mat4::<f32>::from(transform_limb(self.head));
170        let shorts_mat = chest_mat * Mat4::<f32>::from(transform_other(0.6, self.shorts));
171        let control_mat = chest_mat * Mat4::<f32>::from(self.control);
172        let control_l_mat = control_mat * Mat4::<f32>::from(self.control_l);
173        let control_r_mat = control_mat * Mat4::<f32>::from(self.control_r);
174        let hand_r_mat = control_r_mat * Mat4::<f32>::from(transform_limb(self.hand_r));
175
176        let hand_l_mat = Mat4::<f32>::from(transform_limb(self.hand_l));
177        let lantern_mat = if self.holding_lantern {
178            hand_r_mat
179        } else {
180            shorts_mat
181        } * Mat4::<f32>::from(self.lantern);
182        let main_mat = control_l_mat * Mat4::<f32>::from(self.main);
183        let second_mat = control_r_mat * Mat4::<f32>::from(self.second);
184        let glider_mat = chest_mat * Mat4::<f32>::from(self.glider);
185
186        let computed_skeleton = ComputedCharacterSkeleton {
187            head: head_mat,
188            chest: chest_mat,
189            belt: chest_mat * Mat4::<f32>::from(transform_other(1.1, self.belt)),
190            back: chest_mat * Mat4::<f32>::from(self.back),
191            shorts: shorts_mat,
192            hand_l: control_l_mat * hand_l_mat,
193            hand_r: hand_r_mat,
194            foot_l: torso_mat * Mat4::<f32>::from(self.foot_l),
195            foot_r: torso_mat * Mat4::<f32>::from(self.foot_r),
196            shoulder_l: chest_mat * Mat4::<f32>::from(self.shoulder_l),
197            shoulder_r: chest_mat * Mat4::<f32>::from(self.shoulder_r),
198            glider: glider_mat,
199            main: main_mat,
200            second: second_mat,
201            lantern: lantern_mat,
202            // FIXME: Should this be control_l_mat?
203            hold: control_mat * hand_l_mat * Mat4::<f32>::from(self.hold),
204        };
205
206        computed_skeleton.set_figure_bone_data(buf);
207        computed_skeleton
208    }
209}
210
211pub struct SkeletonAttr {
212    scaler: f32,
213    head_scale: f32,
214    head: (f32, f32),
215    chest: (f32, f32),
216    belt: (f32, f32),
217    back: (f32, f32),
218    shorts: (f32, f32),
219    hand: (f32, f32, f32),
220    foot: (f32, f32, f32),
221    shoulder: (f32, f32, f32),
222    lantern: (f32, f32, f32),
223    shl: (f32, f32, f32, f32, f32, f32),
224    shr: (f32, f32, f32, f32, f32, f32),
225    sc: (f32, f32, f32, f32, f32, f32),
226    hhl: (f32, f32, f32, f32, f32, f32),
227    hhr: (f32, f32, f32, f32, f32, f32),
228    hc: (f32, f32, f32, f32, f32, f32),
229    sthl: (f32, f32, f32, f32, f32, f32),
230    sthr: (f32, f32, f32, f32, f32, f32),
231    stc: (f32, f32, f32, f32, f32, f32),
232    ahl: (f32, f32, f32, f32, f32, f32),
233    ahr: (f32, f32, f32, f32, f32, f32),
234    ac: (f32, f32, f32, f32, f32, f32),
235    bhl: (f32, f32, f32, f32, f32, f32),
236    bhr: (f32, f32, f32, f32, f32, f32),
237    bc: (f32, f32, f32, f32, f32, f32),
238}
239
240impl Default for SkeletonAttr {
241    fn default() -> Self {
242        Self {
243            scaler: 0.0,
244            head_scale: 0.0,
245            head: (0.0, 0.0),
246            chest: (0.0, 0.0),
247            belt: (0.0, 0.0),
248            back: (0.0, 0.0),
249            shorts: (0.0, 0.0),
250            hand: (0.0, 0.0, 0.0),
251            foot: (0.0, 0.0, 0.0),
252            shoulder: (0.0, 0.0, 0.0),
253            lantern: (0.0, 0.0, 0.0),
254            shl: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
255            shr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
256            sc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
257            hhl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
258            hhr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
259            hc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
260            sthl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
261            sthr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
262            stc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
263            ahl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
264            ahr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
265            ac: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
266            bhl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
267            bhr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
268            bc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
269        }
270    }
271}
272
273impl<'a> TryFrom<&'a comp::Body> for SkeletonAttr {
274    type Error = ();
275
276    fn try_from(body: &'a comp::Body) -> Result<Self, Self::Error> {
277        match body {
278            comp::Body::Humanoid(body) => Ok(SkeletonAttr::from(body)),
279            _ => Err(()),
280        }
281    }
282}
283
284impl<'a> From<&'a Body> for SkeletonAttr {
285    fn from(body: &'a Body) -> Self {
286        use comp::humanoid::{BodyType::*, Species::*};
287        Self {
288            scaler: body.scaler(),
289            head_scale: match (body.species, body.body_type) {
290                (Orc, Male) => 0.9,
291                (Orc, Female) => 0.9,
292                (Human, Male) => 0.9,
293                (Human, Female) => 0.9,
294                (Elf, Male) => 0.9,
295                (Elf, Female) => 0.9,
296                (Dwarf, Male) => 1.0,
297                (Dwarf, Female) => 1.0,
298                (Draugr, Male) => 0.9,
299                (Draugr, Female) => 0.9,
300                (Danari, Male) => 1.15,
301                (Danari, Female) => 1.15,
302            },
303            head: match (body.species, body.body_type) {
304                (Orc, Male) => (-2.0, 9.0),
305                (Orc, Female) => (-2.0, 9.5),
306                (Human, Male) => (-2.3, 9.5),
307                (Human, Female) => (-2.0, 9.5),
308                (Elf, Male) => (-2.5, 9.5),
309                (Elf, Female) => (-1.0, 9.5),
310                (Dwarf, Male) => (-2.0, 10.0),
311                (Dwarf, Female) => (-2.0, 9.5),
312                (Draugr, Male) => (-1.5, 8.5),
313                (Draugr, Female) => (-1.5, 9.5),
314                (Danari, Male) => (-1.5, 7.0),
315                (Danari, Female) => (-1.5, 7.0),
316            },
317            chest: (0.0, 8.0),
318            belt: (0.0, -2.0),
319            back: (-3.1, 7.25),
320            shorts: (0.0, -5.0),
321            hand: (7.0, -0.25, 0.5),
322            foot: (3.4, 0.5, 2.0),
323            shoulder: (5.0, 0.0, 5.0),
324            lantern: (5.0, 2.5, 5.5),
325            shl: (-0.75, -1.0, 0.5, 1.47, -0.2, 0.0),
326            shr: (0.75, -1.5, -2.5, 1.47, 0.3, 0.0),
327            sc: (-6.0, 6.0, 0.0, -0.5, 0.0, 0.0),
328            hhl: (0.1, 0.0, 11.0, 4.71, 0.0, PI),
329            hhr: (0.0, 0.0, 0.0, 4.71, 0.0, PI),
330            hc: (6.0, 7.0, 1.0, -0.3, -PI / 2.0, 3.64),
331            sthl: (0.0, 0.0, 6.0, 1.97, 0.0, 0.0),
332            sthr: (0.0, 0.0, 0.0, 1.27, 0.2, 0.0),
333            stc: (-5.0, 7.0, -2.0, -0.3, 0.15, 0.0),
334            ahl: (-0.5, -1.5, 5.25, 1.5, PI, 0.0),
335            ahr: (0.0, -2.0, 1.0, 1.5, 0.0, PI),
336            ac: (-8.5, 2.0, 0.5, 4.25, PI, 0.2),
337            bhl: (0.0, -4.0, 1.0, PI / 2.0, 0.0, 0.0),
338            bhr: (1.0, 2.0, -2.0, PI / 2.0, 0.0, 0.0),
339            bc: (-5.0, 9.0, 1.0, 0.0, 1.2, -0.6),
340        }
341    }
342}
343
344pub fn mount_mat(
345    computed_skeleton: &ComputedCharacterSkeleton,
346    skeleton: &CharacterSkeleton,
347) -> (Mat4<f32>, Quaternion<f32>) {
348    (
349        computed_skeleton.chest,
350        skeleton.torso.orientation * skeleton.chest.orientation * Quaternion::rotation_y(0.4),
351    )
352}
353
354pub fn mount_transform(
355    computed_skeleton: &ComputedCharacterSkeleton,
356    skeleton: &CharacterSkeleton,
357) -> Transform<f32, f32, f32> {
358    let (mount_mat, orientation) = mount_mat(computed_skeleton, skeleton);
359    Transform {
360        position: mount_mat.mul_point(Vec3::new(5.5, 0.0, 6.5)),
361        orientation,
362        scale: Vec3::one(),
363    }
364}
365
366impl CharacterSkeleton {
367    /// Animate tools (main and secondary) on the character's back, taking in
368    /// account backpack offsets.
369    pub fn do_tools_on_back(
370        &mut self,
371        hands: (Option<Hands>, Option<Hands>),
372        active_tool_kind: Option<ToolKind>,
373        second_tool_kind: Option<ToolKind>,
374    ) {
375        match (hands, active_tool_kind, second_tool_kind) {
376            ((Some(Hands::Two), _), tool, _) | ((None, Some(Hands::Two)), _, tool) => match tool {
377                Some(ToolKind::Bow) => {
378                    self.main.position = Vec3::new(0.0, -5.0 - self.back_carry_offset, 6.0);
379                    self.main.orientation =
380                        Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
381                },
382                Some(ToolKind::Staff) | Some(ToolKind::Sceptre) => {
383                    self.main.position = Vec3::new(2.0, -5.0 - self.back_carry_offset, -1.0);
384                    self.main.orientation =
385                        Quaternion::rotation_y(-0.5) * Quaternion::rotation_z(PI / 2.0);
386                },
387                Some(ToolKind::Shield) => {
388                    self.main.position = Vec3::new(-2.0, -3.0 - self.back_carry_offset, 1.0);
389                    self.main.orientation =
390                        Quaternion::rotation_y(-0.75) * Quaternion::rotation_z(PI / 2.0);
391                },
392                _ => {
393                    self.main.position = Vec3::new(-7.0, -5.0 - self.back_carry_offset, 15.0);
394                    self.main.orientation =
395                        Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
396                },
397            },
398            ((_, _), _, _) => {},
399        }
400
401        match hands {
402            (Some(Hands::One), _) => match active_tool_kind {
403                Some(ToolKind::Dagger) => {
404                    self.main.position = Vec3::new(5.0, 1.0 - self.back_carry_offset, 2.0);
405                    self.main.orientation =
406                        Quaternion::rotation_x(-1.35 * PI) * Quaternion::rotation_z(2.0 * PI);
407                },
408                Some(ToolKind::Axe) | Some(ToolKind::Hammer) | Some(ToolKind::Sword) => {
409                    self.main.position = Vec3::new(-4.0, -4.5 - self.back_carry_offset, 10.0);
410                    self.main.orientation =
411                        Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
412                },
413                Some(ToolKind::Shield) => {
414                    self.main.position = Vec3::new(-2.0, -4.0 - self.back_carry_offset, 3.0);
415                    self.main.orientation =
416                        Quaternion::rotation_y(0.25 * PI) * Quaternion::rotation_z(-1.5 * PI);
417                },
418                Some(ToolKind::Throwable) => {
419                    self.main.position = Vec3::new(-6.0, 0.0, -4.0);
420                    self.main.scale = Vec3::zero();
421                },
422                _ => {},
423            },
424            (_, _) => {},
425        }
426        match hands {
427            (None | Some(Hands::One), Some(Hands::One)) => match second_tool_kind {
428                Some(ToolKind::Dagger) => {
429                    self.second.position = Vec3::new(-5.0, 1.0 - self.back_carry_offset, 2.0);
430                    self.second.orientation =
431                        Quaternion::rotation_x(-1.35 * PI) * Quaternion::rotation_z(-2.0 * PI);
432                },
433                Some(ToolKind::Axe) | Some(ToolKind::Hammer) | Some(ToolKind::Sword) => {
434                    self.second.position = Vec3::new(4.0, -5.0 - self.back_carry_offset, 10.0);
435                    self.second.orientation =
436                        Quaternion::rotation_y(-2.5) * Quaternion::rotation_z(-PI / 2.0);
437                },
438                Some(ToolKind::Shield) => {
439                    self.second.position = Vec3::new(1.5, -4.0 - self.back_carry_offset, 3.0);
440                    self.second.orientation =
441                        Quaternion::rotation_y(-0.25 * PI) * Quaternion::rotation_z(1.5 * PI);
442                },
443                Some(ToolKind::Throwable) => {
444                    self.second.position = Vec3::new(6.0, 0.0, -4.0);
445                    self.second.scale = Vec3::zero();
446                },
447                _ => {},
448            },
449            (_, _) => {},
450        }
451    }
452
453    /// If we're holding a lantern, animate hold the lantern in a reasonable
454    /// position.
455    pub fn do_hold_lantern(
456        &mut self,
457        s_a: &SkeletonAttr,
458        anim_time: f32,
459        acc_vel: f32,
460        speednorm: f32,
461        impact: f32,
462        tilt: f32,
463        last_ori: Option<Vec3<f32>>,
464        look_dir: Option<Vec3<f32>>,
465    ) {
466        let align_with_cam = look_dir
467            .zip(last_ori)
468            .map_or(0.0, |(l, o)| (l.xy().dot(o.xy()) * 0.5 + 0.5).max(0.0));
469
470        let lab = 2.0 / s_a.scaler;
471
472        let shorte = ((1.0 / (0.8 + 0.2 * ((acc_vel * lab * 1.6).sin()).powi(2))).sqrt())
473            * ((acc_vel * lab * 1.6).sin());
474
475        self.lantern.scale = Vec3::one() * 0.65;
476
477        if self.holding_lantern {
478            let pitch =
479                look_dir.unwrap_or_default().z.clamp(-1.0, 1.0) * (align_with_cam * 5.0).min(1.0);
480            let yaw = look_dir.zip(last_ori).map_or(0.0, |(l, o)| {
481                l.xy().angle_between(o.xy()).min(1.0)
482                    * l.xy().determine_side(Vec2::zero(), o.xy()).signum()
483            }) * (align_with_cam * 15.0).min(1.0);
484
485            let fast = (anim_time * 8.0).sin();
486            let fast2 = (anim_time * 6.0 + 8.0).sin();
487            let breathe = anim_time.sin();
488
489            self.hand_r.position = Vec3::new(
490                s_a.hand.0 + 0.5 - yaw * 3.0,
491                s_a.hand.1 + 3.0 - impact * 0.2 + yaw * 3.5 - breathe * 1.0,
492                s_a.hand.2 + 12.0 + impact * -0.1 + pitch * 1.5 + breathe * 0.5,
493            );
494            self.hand_r.orientation = Quaternion::rotation_z(yaw * 1.0)
495                * Quaternion::rotation_x(2.25 + pitch + breathe * 0.3)
496                * Quaternion::rotation_z(0.9);
497
498            self.control_r.position = Vec3::zero();
499            self.control_r.orientation = Quaternion::rotation_x(0.0)
500                * Quaternion::rotation_y(0.0)
501                * Quaternion::rotation_z(0.0);
502
503            self.shoulder_r.position.z += 3.0;
504            self.shoulder_r.orientation = Quaternion::rotation_z(yaw.min(0.0) * 1.0)
505                * Quaternion::rotation_x(2.25 + breathe * 0.1);
506
507            self.head.position.x += yaw;
508            self.head.position.y -= pitch.min(0.0) * 1.5 - yaw.abs();
509            self.head.orientation = self.head.orientation
510                * Quaternion::rotation_z(yaw)
511                * Quaternion::rotation_x(pitch * 0.6);
512
513            self.chest.orientation = self.chest.orientation * Quaternion::rotation_x(pitch * 0.3);
514
515            self.lantern.position = Vec3::new(-0.5, -0.5, -2.5);
516            self.lantern.orientation = self.hand_r.orientation.inverse()
517                * self.chest.orientation.inverse()
518                * Quaternion::rotation_x(
519                    (fast + 0.5) * 0.1 * speednorm
520                        + (tilt.abs() * 2.0).min(PI * 0.5) * (0.25 + speednorm)
521                        + pitch
522                        + breathe * 0.05,
523                )
524                * Quaternion::rotation_y(tilt * 1.0 * fast + tilt * 1.0 + fast2 * speednorm * 0.25)
525                * Quaternion::rotation_z(yaw)
526                * Quaternion::slerp(Default::default(), self.chest.orientation, 0.3);
527        } else {
528            self.lantern.position = Vec3::new(s_a.lantern.0, s_a.lantern.1, s_a.lantern.2);
529            self.lantern.orientation =
530                Quaternion::slerp(
531                    Default::default(),
532                    self.chest.orientation.inverse() * self.shorts.orientation.inverse(),
533                    0.75,
534                ) * Quaternion::rotation_x(shorte * 0.0 * speednorm.powi(2) + 0.25)
535                    * Quaternion::rotation_y(shorte * 0.2 * speednorm.powi(2) - 0.3);
536        }
537    }
538}
539
540pub fn hammer_start(next: &mut CharacterSkeleton, s_a: &SkeletonAttr) {
541    next.main.position = Vec3::new(0.0, 0.0, 0.0);
542    next.main.orientation = Quaternion::rotation_z(0.0);
543    next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1 + 3.0, s_a.hhl.2 - 1.0);
544    next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3)
545        * Quaternion::rotation_y(s_a.hhl.4)
546        * Quaternion::rotation_z(s_a.hhl.5);
547    next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1 + 3.0, s_a.hhr.2 + 1.0);
548    next.hand_r.orientation = Quaternion::rotation_x(s_a.hhr.3)
549        * Quaternion::rotation_y(s_a.hhr.4)
550        * Quaternion::rotation_z(s_a.hhr.5);
551
552    next.control.position = Vec3::new(s_a.hc.0 - 1.0, s_a.hc.1, s_a.hc.2 - 3.0);
553    next.control.orientation = Quaternion::rotation_x(s_a.hc.3)
554        * Quaternion::rotation_y(s_a.hc.4)
555        * Quaternion::rotation_z(s_a.hc.5);
556}
557
558pub fn bow_start(next: &mut CharacterSkeleton, s_a: &SkeletonAttr) {
559    next.main.position = Vec3::new(0.0, 0.0, 0.0);
560    next.main.orientation = Quaternion::rotation_x(0.0);
561    next.hand_l.position = Vec3::new(s_a.bhl.0 - 1.0, s_a.bhl.1, s_a.bhl.2);
562    next.hand_l.orientation = Quaternion::rotation_x(s_a.bhl.3);
563    next.hand_r.position = Vec3::new(s_a.bhr.0, s_a.bhr.1, s_a.bhr.2);
564    next.hand_r.orientation = Quaternion::rotation_x(s_a.bhr.3);
565
566    next.hold.orientation = Quaternion::rotation_x(-PI / 2.0);
567    next.hold.scale = Vec3::one();
568
569    next.control.position = Vec3::new(s_a.bc.0, s_a.bc.1, s_a.bc.2);
570    next.control.orientation = Quaternion::rotation_y(s_a.bc.4) * Quaternion::rotation_z(s_a.bc.5);
571
572    next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
573}
574
575pub fn bow_draw(next: &mut CharacterSkeleton, move1: f32, look_dir_z: f32) {
576    next.control.position += Vec3::new(
577        7.0 + look_dir_z.abs() * -4.0,
578        2.0 + look_dir_z.abs() * -5.0,
579        8.0 + look_dir_z * 15.0,
580    ) * move1;
581    next.control.orientation.rotate_y(move1 * -1.25);
582    next.control
583        .orientation
584        .rotate_z((-0.2 + look_dir_z.abs() * 0.8) * move1);
585    next.control.orientation.rotate_x(look_dir_z * 1.6 * move1);
586
587    next.head.orientation = Quaternion::rotation_x(look_dir_z * 0.7 * move1);
588    next.chest.orientation = Quaternion::rotation_z(0.8 * move1);
589}
590
591pub fn twist_back(next: &mut CharacterSkeleton, move1: f32, c: f32, h: f32, b: f32, s: f32) {
592    next.chest.orientation.rotate_z(move1 * c);
593    next.head.orientation.rotate_z(move1 * -h);
594    next.belt.orientation.rotate_z(move1 * -b);
595    next.shorts.orientation.rotate_z(move1 * -s);
596}
597
598pub fn twist_forward(next: &mut CharacterSkeleton, move2: f32, c: f32, h: f32, b: f32, s: f32) {
599    next.chest.orientation.rotate_z(move2 * -c);
600    next.head.orientation.rotate_z(move2 * h);
601    next.belt.orientation.rotate_z(move2 * b);
602    next.shorts.orientation.rotate_z(move2 * s);
603}
604
605pub fn dual_wield_start(next: &mut CharacterSkeleton) {
606    next.main.position = Vec3::new(0.0, 0.0, 0.0);
607    next.main.orientation = Quaternion::rotation_z(0.0);
608    next.second.position = Vec3::new(0.0, 0.0, 0.0);
609    next.second.orientation = Quaternion::rotation_z(0.0);
610
611    next.control_l.position =
612        next.hand_l.position * Vec3::new(0.5, 0.5, 0.3) + Vec3::new(-4.0, 0.0, 0.0);
613    next.control_l.orientation = Quaternion::lerp(
614        next.hand_l.orientation,
615        Quaternion::rotation_x(PI * -0.5),
616        0.65,
617    );
618    next.hand_l.position = Vec3::new(0.0, -2.0, 0.0);
619    next.hand_l.orientation = Quaternion::rotation_x(PI * 0.5);
620
621    next.control_r.position =
622        next.hand_r.position * Vec3::new(0.5, 0.5, 0.3) + Vec3::new(4.0, 0.0, 0.0);
623    next.control_r.orientation = Quaternion::lerp(
624        next.hand_r.orientation,
625        Quaternion::rotation_x(PI * -0.5),
626        0.65,
627    );
628    next.hand_r.position = Vec3::new(0.0, -2.0, 0.0);
629    next.hand_r.orientation = Quaternion::rotation_x(PI * 0.5);
630}