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}