veloren_voxygen_anim/biped_small/
combomelee.rs

1use std::f32::consts::PI;
2
3use super::{
4    super::{Animation, vek::*},
5    BipedSmallSkeleton, SkeletonAttr, biped_small_alpha_axe, biped_small_alpha_dagger,
6    biped_small_alpha_spear, biped_small_wield_spear, init_biped_small_alpha,
7};
8use common::states::utils::StageSection;
9
10pub struct ComboAnimation;
11impl Animation for ComboAnimation {
12    type Dependency<'a> = (Option<&'a str>, StageSection, usize, Vec3<f32>, f32, f32);
13    type Skeleton = BipedSmallSkeleton;
14
15    #[cfg(feature = "use-dyn-lib")]
16    const UPDATE_FN: &'static [u8] = b"biped_small_combo\0";
17
18    #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "biped_small_combo"))]
19    fn update_skeleton_inner(
20        skeleton: &Self::Skeleton,
21        (ability_id, stage_section, current_strike, velocity, _global_time, _timer): Self::Dependency<'_>,
22        anim_time: f32,
23        rate: &mut f32,
24        s_a: &SkeletonAttr,
25    ) -> Self::Skeleton {
26        *rate = 1.0;
27        let mut next = (*skeleton).clone();
28
29        next.main.position = Vec3::new(0.0, 0.0, 0.0);
30        next.main.orientation = Quaternion::rotation_z(0.0);
31        next.second.position = Vec3::new(0.0, 0.0, 0.0);
32        next.second.orientation = Quaternion::rotation_z(0.0);
33        let multi_strike_pullback = 1.0
34            - if matches!(stage_section, StageSection::Recover) {
35                anim_time.powi(4)
36            } else {
37                0.0
38            };
39
40        for strike in 0..=current_strike {
41            match ability_id {
42                Some(
43                    "common.abilities.custom.bushly.singlestrike"
44                    | "common.abilities.custom.irrwurz.singlestrike"
45                    | "common.abilities.custom.husk.singlestrike"
46                    | "common.abilities.custom.husk.triplestrike"
47                    | "common.abilities.custom.dwarves.iron_dwarf.singlestrike"
48                    | "common.abilities.custom.dwarves.iron_dwarf.triplestrike",
49                ) => {
50                    let (move1, move2) = if strike == current_strike {
51                        match stage_section {
52                            StageSection::Buildup => {
53                                (((anim_time.max(0.4) - 0.4) * 1.5).powf(0.5), 0.0)
54                            },
55                            StageSection::Action => (1.0, (anim_time.min(0.4) * 2.5).powi(2)),
56                            StageSection::Recover => (1.0, 1.0),
57                            _ => (0.0, 0.0),
58                        }
59                    } else {
60                        (1.0, 1.0)
61                    };
62                    let move1 = move1 * multi_strike_pullback;
63                    let move2 = move2 * multi_strike_pullback;
64                    next.hand_l.position = Vec3::new(s_a.grip.0 * 4.0, 0.0, s_a.grip.2);
65                    next.hand_r.position = Vec3::new(-s_a.grip.0 * 4.0, 0.0, s_a.grip.2);
66                    next.main.position = Vec3::new(0.0, 0.0, 0.0);
67                    next.main.orientation = Quaternion::rotation_x(0.0);
68                    next.hand_l.orientation = Quaternion::rotation_x(0.0);
69                    next.hand_r.orientation = Quaternion::rotation_x(0.0);
70
71                    match strike {
72                        0..=2 => {
73                            next.chest.orientation = Quaternion::rotation_x(move2 * -1.0)
74                                * Quaternion::rotation_z(move1 * 1.2 + move2 * -1.8);
75                            next.hand_l.position = Vec3::new(-s_a.hand.0, s_a.hand.1, s_a.hand.2);
76                            next.hand_l.orientation = Quaternion::rotation_x(1.2);
77                            next.hand_r.position = Vec3::new(s_a.hand.0, s_a.hand.1, s_a.hand.2);
78                            next.hand_r.orientation = Quaternion::rotation_x(1.2);
79                        },
80                        _ => {},
81                    }
82                },
83                Some("common.abilities.custom.cactid.singlestrike") => {
84                    let (move1, move2) = if strike == current_strike {
85                        match stage_section {
86                            StageSection::Buildup => {
87                                (((anim_time.max(0.4) - 0.4) * 1.5).powf(0.5), 0.0)
88                            },
89                            StageSection::Action => (1.0, (anim_time.min(0.4) * 2.5).powi(2)),
90                            StageSection::Recover => (1.0, 1.0),
91                            _ => (0.0, 0.0),
92                        }
93                    } else {
94                        (1.0, 1.0)
95                    };
96                    let move1 = move1 * multi_strike_pullback;
97                    let move2 = move2 * multi_strike_pullback;
98                    next.hand_l.position = Vec3::new(s_a.grip.0 * 4.0, 0.0, s_a.grip.2);
99                    next.hand_r.position = Vec3::new(-s_a.grip.0 * 4.0, 0.0, s_a.grip.2);
100                    next.main.position = Vec3::new(0.0, 0.0, 0.0);
101                    next.main.orientation = Quaternion::rotation_x(0.0);
102                    next.hand_l.orientation = Quaternion::rotation_x(0.0);
103                    next.hand_r.orientation = Quaternion::rotation_x(0.0);
104                    next.head.orientation = Quaternion::rotation_z(move2 * 1.0);
105
106                    next.chest.orientation = Quaternion::rotation_x(move2 * -1.0)
107                        * Quaternion::rotation_z(move1 * -1.2 + move2 * 1.8);
108                    next.hand_l.position = Vec3::new(-s_a.hand.0, s_a.hand.1, s_a.hand.2);
109                    next.hand_l.orientation = Quaternion::rotation_x(1.2);
110                    next.hand_r.position = Vec3::new(s_a.hand.0, s_a.hand.1, s_a.hand.2);
111                    next.hand_r.orientation = Quaternion::rotation_x(1.2);
112                },
113                Some(
114                    "common.abilities.axesimple.doublestrike"
115                    | "common.abilities.custom.goblin_thug.doublestrike"
116                    | "common.abilities.custom.green_legoom.doublestrike"
117                    | "common.abilities.custom.red_legoom.doublestrike"
118                    | "common.abilities.vampire.bloodservant.doublestrike"
119                    | "common.abilities.custom.boreal_warrior.hammer.singlestrike",
120                ) => {
121                    let anim_time = anim_time.min(1.0);
122                    let (move1base, move2base, move3) = match stage_section {
123                        StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0),
124                        StageSection::Action => (1.0, anim_time.powi(4), 0.0),
125                        StageSection::Recover => (1.0, 1.0, anim_time),
126                        _ => (0.0, 0.0, 0.0),
127                    };
128                    let pullback = 1.0 - move3;
129                    let move1abs = move1base * pullback;
130                    let move2abs = move2base * pullback;
131
132                    init_biped_small_alpha(&mut next, s_a);
133                    biped_small_alpha_axe(&mut next, s_a, move1abs, move2abs);
134                },
135                Some("common.abilities.custom.umber_legoom.doublestrike") => {
136                    let anim_time = anim_time.min(1.0);
137                    let (move1base, move2base) = if strike == current_strike {
138                        match stage_section {
139                            StageSection::Buildup => (anim_time.sqrt(), 0.0),
140                            StageSection::Action => (1.0, anim_time.powi(4)),
141                            StageSection::Recover => (1.0, 1.0),
142                            _ => (0.0, 0.0),
143                        }
144                    } else {
145                        (1.0, 1.0)
146                    };
147                    let move1 = move1base * multi_strike_pullback;
148                    let move2 = move2base * multi_strike_pullback;
149                    next.chest.orientation =
150                        Quaternion::rotation_z(PI * 0.45 * move1 - PI * 1.0 * move2);
151                    next.hand_r.position = Vec3::new(0.5, 2.0, 0.5);
152                    next.hand_r.orientation = Quaternion::rotation_x(PI * 0.45);
153                    next.hand_l.position = Vec3::new(-0.5, 2.0, 0.5);
154                    next.hand_l.orientation = Quaternion::rotation_x(PI * 0.45);
155                    match strike {
156                        0 => {
157                            next.head.orientation =
158                                Quaternion::rotation_z(-PI * 0.3 * move1 + PI * 0.6 * move2);
159
160                            next.main.position = Vec3::new(-1.0, 10.0, -3.0);
161                        },
162                        _ => {
163                            next.head.orientation =
164                                Quaternion::rotation_z(-PI * 0.3 * move1 + PI * 0.6 * move2)
165                                    * Quaternion::rotation_x(PI / 8.0 * move1 - PI / 8.0 * move2);
166
167                            next.control
168                                .orientation
169                                .rotate_x(PI / 8.0 * move1 - PI / 8.0 * move2);
170
171                            next.main.position = Vec3::new(-1.0 + 4.0 * move2, 10.0, -3.0);
172                            next.main.orientation = Quaternion::rotation_y(-PI / 3.0 * move2);
173                        },
174                    }
175                },
176                Some("common.abilities.custom.ashen_warrior.axe.doublestrike") => {
177                    let anim_time = anim_time.min(1.0);
178                    let (move1base, move2base) = if strike == current_strike {
179                        match stage_section {
180                            StageSection::Buildup => (anim_time.sqrt(), 0.0),
181                            StageSection::Action => (1.0, anim_time.powi(4)),
182                            StageSection::Recover => (1.0, 1.0),
183                            _ => (0.0, 0.0),
184                        }
185                    } else {
186                        (1.0, 1.0)
187                    };
188                    let move1 = move1base * multi_strike_pullback;
189                    let move2 = move2base * multi_strike_pullback;
190
191                    match strike {
192                        0 => {
193                            next.main.position = Vec3::new(-8.0, 2.0, 0.0);
194                            next.main.orientation = Quaternion::rotation_x(0.0);
195                            next.second.position = Vec3::new(8.0, 2.0, 0.0);
196                            next.second.orientation = Quaternion::rotation_x(0.0);
197                            next.hand_l.position = Vec3::new(s_a.grip.0 * 4.0, 0.0, 2.0);
198                            next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0);
199                            next.hand_r.position = Vec3::new(-s_a.grip.0 * 4.0, 0.0, 2.0);
200                            next.hand_r.orientation = Quaternion::rotation_x(PI / 2.0);
201
202                            next.chest.orientation.rotate_z(PI / 4.0 * move1);
203                            next.pants.orientation.rotate_z(-PI / 8.0 * move1);
204                            next.hand_l.position += Vec3::new(0.0, 0.0, 2.0) * move1;
205                            next.hand_l.orientation.rotate_y(-PI / 8.0 * move1);
206                            next.main.orientation.rotate_y(-PI / 8.0 * move1);
207                            next.control_r.orientation.rotate_y(-PI / 8.0 * move1);
208
209                            next.chest.orientation.rotate_z(-PI / 2.5 * move2);
210                            next.pants.orientation.rotate_z(PI / 8.0 * move2);
211                            next.hand_l.position += Vec3::new(0.0, 5.0, -3.0) * move2;
212                            next.hand_l.orientation.rotate_x(-PI / 3.0 * move2);
213                            next.hand_l.orientation.rotate_y(-PI / 4.0 * move2);
214                            next.hand_l.orientation.rotate_z(-PI / 4.0 * move2);
215                            next.main.position += Vec3::new(0.0, 5.0, -3.0) * move2;
216                            next.main.orientation.rotate_x(-PI / 3.0 * move2);
217                            next.main.orientation.rotate_y(-PI / 4.0 * move2);
218                            next.main.orientation.rotate_z(-PI / 4.0 * move2);
219                        },
220                        1 => {
221                            next.chest.orientation.rotate_z(-PI / 5.0 * move1);
222                            next.control_r.orientation.rotate_y(PI / 4.0 * move1);
223
224                            next.chest.orientation.rotate_z(PI / 2.0 * move2);
225                            next.hand_l.position += Vec3::new(0.0, -4.0, 0.0) * move2;
226                            next.hand_l.orientation.rotate_x(PI / 6.0 * move2);
227                            next.hand_l.orientation.rotate_y(PI / 8.0 * move2);
228                            next.hand_l.orientation.rotate_z(PI / 8.0 * move2);
229                            next.main.position += Vec3::new(0.0, -4.0, 0.0) * move2;
230                            next.main.orientation.rotate_x(PI / 6.0 * move2);
231                            next.main.orientation.rotate_y(PI / 8.0 * move2);
232                            next.main.orientation.rotate_z(PI / 8.0 * move2);
233                            next.control_r.orientation.rotate_x(-PI / 4.0 * move2);
234                            next.control_r.orientation.rotate_y(PI / 8.0 * move2);
235                            next.control_r.orientation.rotate_z(PI / 8.0 * move2);
236                        },
237                        _ => {},
238                    }
239                },
240                Some("common.abilities.custom.ashen_warrior.axe.knockback_combo") => {
241                    let anim_time = anim_time.min(1.0);
242                    let (move1base, move2base, move3base) = if strike == current_strike {
243                        match stage_section {
244                            StageSection::Buildup => (anim_time, 0.0, 0.0),
245                            StageSection::Action => (1.0, anim_time, 0.0),
246                            StageSection::Recover => (1.0, 1.0, anim_time),
247                            _ => (0.0, 0.0, 0.0),
248                        }
249                    } else {
250                        (1.0, 1.0, 1.0)
251                    };
252                    let multi_strike_pullback = 1.0 - move3base;
253                    let move1 = move1base * multi_strike_pullback;
254                    let move2 = move2base * multi_strike_pullback;
255
256                    match strike {
257                        0 => {
258                            next.main.position = Vec3::new(-8.0, 2.0, 0.0);
259                            next.main.orientation = Quaternion::rotation_x(0.0);
260                            next.second.position = Vec3::new(8.0, 2.0, 0.0);
261                            next.second.orientation = Quaternion::rotation_x(0.0);
262                            next.hand_l.position = Vec3::new(s_a.grip.0 * 4.0, 0.0, 2.0);
263                            next.hand_l.orientation = Quaternion::rotation_x(PI / 2.0);
264                            next.hand_r.position = Vec3::new(-s_a.grip.0 * 4.0, 0.0, 2.0);
265                            next.hand_r.orientation = Quaternion::rotation_x(PI / 2.0);
266
267                            next.hand_l.position += Vec3::new(-6.0, 0.0, -4.0) * move1;
268                            next.hand_l.orientation.rotate_y(PI / 1.3 * move1);
269                            next.main.position += Vec3::new(0.0, 0.0, 4.0) * move1;
270                            next.main.orientation.rotate_y(PI / 1.3 * move1);
271                            next.control_r.position += Vec3::new(15.0, 0.0, -5.0) * move1;
272                            next.control_r.orientation.rotate_y(-PI / 1.3 * move1);
273                            next.chest.orientation.rotate_x(-PI / 12.0 * move1);
274                            next.pants.orientation.rotate_x(PI / 12.0 * move1);
275
276                            next.control_r.orientation.rotate_x(PI / 2.0 * move2);
277                            next.control_r.orientation.rotate_y(PI / 2.0 * move2);
278                            next.control_r.orientation.rotate_z(-PI / 4.0 * move2);
279                            next.hand_l.orientation.rotate_x(PI / 2.0 * move2);
280                            next.hand_l.orientation.rotate_y(-PI / 2.0 * move2);
281                            next.hand_l.orientation.rotate_z(PI / 4.0 * move2);
282                            next.main.orientation.rotate_x(PI / 2.0 * move2);
283                            next.main.orientation.rotate_y(-PI / 2.0 * move2);
284                            next.main.orientation.rotate_z(PI / 4.0 * move2);
285                            next.chest.orientation.rotate_x(PI / 8.0 * move2);
286                            next.pants.orientation.rotate_x(-PI / 8.0 * move2);
287                        },
288                        1 => {
289                            let rotate_about =
290                                |bone: &mut Transform<f32, f32, f32>,
291                                 pivot: Vec3<f32>,
292                                 rotation: Quaternion<f32>| {
293                                    bone.orientation = bone.orientation * rotation;
294                                    bone.position = rotation * (bone.position - pivot) + pivot;
295                                };
296
297                            next.chest.orientation.rotate_x(PI * move1base);
298                            rotate_about(
299                                &mut next.foot_l,
300                                next.chest.position,
301                                Quaternion::rotation_x(PI * move1base),
302                            );
303                            rotate_about(
304                                &mut next.foot_r,
305                                next.chest.position,
306                                Quaternion::rotation_x(PI * move1base),
307                            );
308                            next.pants.orientation.rotate_x(PI / 4.0 * move1);
309                            next.foot_l.orientation.rotate_x(PI / 4.0 * move1);
310                            next.foot_r.orientation.rotate_x(PI / 4.0 * move1);
311                            next.control_r.orientation.rotate_y(-PI / 2.0 * move1);
312                            next.hand_l.orientation.rotate_y(-PI / 2.0 * move1);
313                            next.main.orientation.rotate_y(-PI / 2.0 * move1);
314
315                            next.chest.orientation.rotate_z(2.0 * PI * move2base);
316                            next.foot_l.orientation.rotate_z(2.0 * PI * move2base);
317                            next.foot_r.orientation.rotate_z(2.0 * PI * move2base);
318                            next.pants.orientation.rotate_x(-PI / 4.0 * move2);
319                            next.foot_l.orientation.rotate_x(-PI / 4.0 * move2);
320                            next.foot_r.orientation.rotate_x(-PI / 4.0 * move2);
321
322                            next.chest.orientation.rotate_x(PI * move3base);
323                            rotate_about(
324                                &mut next.foot_l,
325                                next.chest.position,
326                                Quaternion::rotation_x(PI * move3base),
327                            );
328                            rotate_about(
329                                &mut next.foot_r,
330                                next.chest.position,
331                                Quaternion::rotation_x(PI * move3base),
332                            );
333                        },
334                        _ => {},
335                    }
336                },
337                Some("common.abilities.custom.boreal_warrior.bow.doublestrike") => {
338                    let anim_time = anim_time.min(1.0);
339                    let (move1base, move2base) = if strike == current_strike {
340                        match stage_section {
341                            StageSection::Buildup => (anim_time.sqrt(), 0.0),
342                            StageSection::Action => (1.0, anim_time.powi(4)),
343                            StageSection::Recover => (1.0, 1.0),
344                            _ => (0.0, 0.0),
345                        }
346                    } else {
347                        (1.0, 1.0)
348                    };
349                    let move1 = move1base * multi_strike_pullback;
350                    let move2 = move2base * multi_strike_pullback;
351
352                    match strike {
353                        0 => {
354                            init_biped_small_alpha(&mut next, s_a);
355
356                            next.control.position += Vec3::new(0.0, 8.0, 0.0);
357                            next.control.orientation.rotate_x(-PI / 8.0);
358                            next.hand_l.position += Vec3::new(-6.0, -4.0, -4.0);
359                            next.hand_l.orientation.rotate_x(PI / 2.0);
360                            next.hand_l.orientation.rotate_z(-PI / 8.0);
361                            next.hand_r.position += Vec3::new(4.0, -4.0, -6.0);
362                            next.hand_r.orientation.rotate_x(PI / 2.0);
363                            next.hand_r.orientation.rotate_z(PI / 9.0);
364
365                            next.chest.orientation.rotate_z(PI / 4.0 * move1);
366                            next.control.position += Vec3::new(0.0, (PI * move1).cos(), 0.0);
367                            next.control.orientation.rotate_y(-PI / 8.0 * move1);
368                            next.control.orientation.rotate_x(-PI / 8.0 * move1.powi(2));
369
370                            next.control
371                                .orientation
372                                .rotate_y(-PI / 3.0 * f32::from(move2 != 0.0));
373                            next.chest.orientation.rotate_z(-PI / 2.5 * move2);
374                        },
375                        1 => {
376                            next.chest.orientation.rotate_z(-PI / 5.0 * move1);
377                            next.control.position += Vec3::new(0.0, (PI * move1).cos(), 0.0);
378                            next.control.orientation.rotate_y(PI / 2.0 * move1);
379
380                            next.control
381                                .orientation
382                                .rotate_y(PI / 3.0 * f32::from(move2 != 0.0));
383                            next.chest.orientation.rotate_z(PI / 2.0 * move2);
384                        },
385                        _ => {},
386                    }
387                },
388                Some(
389                    "common.abilities.daggersimple.singlestrike"
390                    | "common.abilities.vampire.bloodmoon_heiress.singlestrike",
391                ) => {
392                    let anim_time = anim_time.min(1.0);
393                    let (move1base, move2base, move3) = match stage_section {
394                        StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0),
395                        StageSection::Action => (1.0, anim_time.powi(4), 0.0),
396                        StageSection::Recover => (1.0, 1.0, anim_time),
397                        _ => (0.0, 0.0, 0.0),
398                    };
399                    let pullback = 1.0 - move3;
400                    let move1abs = move1base * pullback;
401                    let move2abs = move2base * pullback;
402
403                    init_biped_small_alpha(&mut next, s_a);
404                    biped_small_alpha_dagger(&mut next, s_a, move1abs, move2abs);
405                },
406                Some(
407                    "common.abilities.spear.doublestrike"
408                    | "common.abilities.custom.purple_legoom.doublestrike",
409                ) => {
410                    let anim_time = anim_time.min(1.0);
411                    let speed = Vec2::<f32>::from(velocity).magnitude();
412                    let speednorm = speed / 9.4;
413                    let speednormcancel = 1.0 - speednorm;
414
415                    let (move1base, move2base, move3) = match stage_section {
416                        StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0),
417                        StageSection::Action => (1.0, anim_time.powi(4), 0.0),
418                        StageSection::Recover => (1.0, 1.0, anim_time),
419                        _ => (0.0, 0.0, 0.0),
420                    };
421                    let pullback = 1.0 - move3;
422                    let move1abs = move1base * pullback;
423                    let move2abs = move2base * pullback;
424
425                    init_biped_small_alpha(&mut next, s_a);
426                    biped_small_alpha_spear(
427                        &mut next,
428                        s_a,
429                        move1abs,
430                        move2abs,
431                        anim_time,
432                        speednormcancel,
433                    );
434                },
435                Some("common.abilities.haniwa.guard.backpedal") => {
436                    init_biped_small_alpha(&mut next, s_a);
437                    biped_small_wield_spear(&mut next, s_a, anim_time, 0.0, 0.0);
438
439                    let (move1, move2, move3) = match stage_section {
440                        StageSection::Buildup => (anim_time.powf(0.25), 0.0, 0.0),
441                        StageSection::Action => (1.0, anim_time, 0.0),
442                        StageSection::Recover => (1.0, 1.0, anim_time.powf(0.25)),
443                        _ => (0.0, 0.0, 0.0),
444                    };
445                    let pullback = 1.0 - move3;
446                    let move1 = move1 * pullback;
447                    let move2 = move2 * pullback;
448
449                    biped_small_alpha_spear(&mut next, s_a, move1, move2, anim_time, 0.0);
450                },
451                _ => {},
452            }
453        }
454        next
455    }
456}