1use crate::{
2 combat::AttackSource,
3 comp::{
4 ControlAction, Density, Energy, InputAttr, InputKind, Ori, Pos, Vel, ability::Capability,
5 inventory::item::armor::Friction, item::ConsumableKind,
6 },
7 event::{self, EmitExt, LocalEvent},
8 event_emitters,
9 resources::Time,
10 states::{
11 self,
12 behavior::{CharacterBehavior, JoinData},
13 utils::{AbilityInfo, StageSection},
14 *,
15 },
16 util::Dir,
17};
18use serde::{Deserialize, Serialize};
19use specs::{Component, DerefFlaggedStorage};
20use std::{collections::BTreeMap, time::Duration};
21use strum::Display;
22
23pub struct StateUpdate {
25 pub character: CharacterState,
26 pub pos: Pos,
27 pub vel: Vel,
28 pub ori: Ori,
29 pub density: Density,
30 pub energy: Energy,
31 pub swap_equipped_weapons: bool,
32 pub should_strafe: bool,
33 pub queued_inputs: BTreeMap<InputKind, InputAttr>,
34 pub removed_inputs: Vec<InputKind>,
35 pub character_activity: CharacterActivity,
36}
37
38event_emitters! {
39 pub struct CharacterStateEvents[CharacterStateEventEmitters] {
40 combo: event::ComboChangeEvent,
41 event: event::AuraEvent,
42 shoot: event::ShootEvent,
43 throw: event::ThrowEvent,
44 teleport_to: event::TeleportToEvent,
45 shockwave: event::ShockwaveEvent,
46 explosion: event::ExplosionEvent,
47 buff: event::BuffEvent,
48 inventory_manip: event::InventoryManipEvent,
49 sprite_summon: event::CreateSpriteEvent,
50 beam_pillar_summon: event::SummonBeamPillarsEvent,
51 change_stance: event::ChangeStanceEvent,
52 create_npc: event::CreateNpcEvent,
53 create_object: event::CreateObjectEvent,
54 energy_change: event::EnergyChangeEvent,
55 knockback: event::KnockbackEvent,
56 sprite_light: event::ToggleSpriteLightEvent,
57 transform: event::TransformEvent,
58 regrow_head: event::RegrowHeadEvent,
59 create_aura_entity: event::CreateAuraEntityEvent,
60 help_downed: event::HelpDownedEvent,
61 }
62}
63
64pub struct OutputEvents<'a, 'b> {
65 local: &'a mut Vec<LocalEvent>,
66 server: &'a mut CharacterStateEventEmitters<'b>,
67}
68
69impl<'a, 'b: 'a> OutputEvents<'a, 'b> {
70 pub fn new(
71 local: &'a mut Vec<LocalEvent>,
72 server: &'a mut CharacterStateEventEmitters<'b>,
73 ) -> Self {
74 Self { local, server }
75 }
76
77 pub fn emit_local(&mut self, event: LocalEvent) { self.local.push(event); }
78
79 pub fn emit_server<E>(&mut self, event: E)
80 where
81 CharacterStateEventEmitters<'b>: EmitExt<E>,
82 {
83 self.server.emit(event);
84 }
85}
86
87impl From<&JoinData<'_>> for StateUpdate {
88 fn from(data: &JoinData) -> Self {
89 StateUpdate {
90 pos: *data.pos,
91 vel: *data.vel,
92 ori: *data.ori,
93 density: *data.density,
94 energy: *data.energy,
95 swap_equipped_weapons: false,
96 should_strafe: data.inputs.strafing,
97 character: data.character.clone(),
98 queued_inputs: BTreeMap::new(),
99 removed_inputs: Vec::new(),
100 character_activity: data.character_activity.clone(),
101 }
102 }
103}
104#[derive(Clone, Debug, Display, PartialEq, Serialize, Deserialize)]
105pub enum CharacterState {
106 Idle(idle::Data),
107 Crawl,
108 Climb(climb::Data),
109 Sit,
110 Dance,
111 Talk(talk::Data),
112 Glide(glide::Data),
113 GlideWield(glide_wield::Data),
114 Stunned(stunned::Data),
116 BasicBlock(basic_block::Data),
118 Equipping(equipping::Data),
120 Wielding(wielding::Data),
122 Roll(roll::Data),
124 BasicMelee(basic_melee::Data),
126 BasicRanged(basic_ranged::Data),
128 Boost(boost::Data),
130 DashMelee(dash_melee::Data),
132 ComboMelee2(combo_melee2::Data),
134 LeapExplosionShockwave(leap_explosion_shockwave::Data),
136 LeapMelee(leap_melee::Data),
138 LeapShockwave(leap_shockwave::Data),
140 ChargedRanged(charged_ranged::Data),
142 ChargedMelee(charged_melee::Data),
144 RepeaterRanged(repeater_ranged::Data),
146 Throw(throw::Data),
148 Shockwave(shockwave::Data),
150 Explosion(explosion::Data),
152 BasicBeam(basic_beam::Data),
155 BasicAura(basic_aura::Data),
157 StaticAura(static_aura::Data),
160 Blink(blink::Data),
162 BasicSummon(basic_summon::Data),
164 SelfBuff(self_buff::Data),
166 SpriteSummon(sprite_summon::Data),
168 UseItem(use_item::Data),
170 Interact(interact::Data),
173 Wallrun(wallrun::Data),
175 Skate(skate::Data),
177 Music(music::Data),
179 FinisherMelee(finisher_melee::Data),
181 DiveMelee(dive_melee::Data),
184 RiposteMelee(riposte_melee::Data),
186 RapidMelee(rapid_melee::Data),
189 Transform(transform::Data),
191 RegrowHead(regrow_head::Data),
193}
194
195impl CharacterState {
196 pub fn is_wield(&self) -> bool {
197 match self {
198 CharacterState::Wallrun(wallrun::Data { was_wielded })
199 | CharacterState::Climb(climb::Data { was_wielded, .. })
200 | CharacterState::Roll(roll::Data { was_wielded, .. })
201 | CharacterState::Stunned(stunned::Data { was_wielded, .. }) => *was_wielded,
202 CharacterState::Wielding(_)
203 | CharacterState::BasicMelee(_)
204 | CharacterState::BasicRanged(_)
205 | CharacterState::Throw(_)
206 | CharacterState::DashMelee(_)
207 | CharacterState::ComboMelee2(_)
208 | CharacterState::BasicBlock(_)
209 | CharacterState::LeapMelee(_)
210 | CharacterState::LeapShockwave(_)
211 | CharacterState::LeapExplosionShockwave(_)
212 | CharacterState::Explosion(_)
213 | CharacterState::ChargedMelee(_)
214 | CharacterState::ChargedRanged(_)
215 | CharacterState::RepeaterRanged(_)
216 | CharacterState::Shockwave(_)
217 | CharacterState::BasicBeam(_)
218 | CharacterState::BasicAura(_)
219 | CharacterState::SelfBuff(_)
220 | CharacterState::Blink(_)
221 | CharacterState::Music(_)
222 | CharacterState::BasicSummon(_)
223 | CharacterState::SpriteSummon(_)
224 | CharacterState::FinisherMelee(_)
225 | CharacterState::DiveMelee(_)
226 | CharacterState::RiposteMelee(_)
227 | CharacterState::RapidMelee(_)
228 | CharacterState::StaticAura(_) => true,
229 CharacterState::Idle(_)
230 | CharacterState::Crawl
231 | CharacterState::Sit
232 | CharacterState::Dance
233 | CharacterState::Talk(_)
234 | CharacterState::Glide(_)
235 | CharacterState::GlideWield(_)
236 | CharacterState::Equipping(_)
237 | CharacterState::Boost(_)
238 | CharacterState::UseItem(_)
239 | CharacterState::Interact(_)
240 | CharacterState::Skate(_)
241 | CharacterState::Transform(_)
242 | CharacterState::RegrowHead(_) => false,
243 }
244 }
245
246 pub fn is_ranged(&self) -> bool {
247 matches!(
248 self,
249 CharacterState::BasicRanged(_)
250 | CharacterState::Throw(_)
251 | CharacterState::ChargedRanged(_)
252 | CharacterState::RepeaterRanged(_)
253 )
254 }
255
256 pub fn can_interact(&self) -> bool {
258 match self {
259 CharacterState::Idle(_)
260 | CharacterState::Sit
261 | CharacterState::Dance
262 | CharacterState::Talk(_)
263 | CharacterState::Equipping(_)
264 | CharacterState::Wielding(_)
265 | CharacterState::GlideWield(_) => true,
266 CharacterState::Crawl
267 | CharacterState::Climb(_)
268 | CharacterState::Glide(_)
269 | CharacterState::Stunned(_)
270 | CharacterState::BasicBlock(_)
271 | CharacterState::Roll(_)
272 | CharacterState::BasicMelee(_)
273 | CharacterState::BasicRanged(_)
274 | CharacterState::Throw(_)
275 | CharacterState::Boost(_)
276 | CharacterState::DashMelee(_)
277 | CharacterState::ComboMelee2(_)
278 | CharacterState::LeapExplosionShockwave(_)
279 | CharacterState::LeapMelee(_)
280 | CharacterState::LeapShockwave(_)
281 | CharacterState::ChargedRanged(_)
282 | CharacterState::ChargedMelee(_)
283 | CharacterState::RepeaterRanged(_)
284 | CharacterState::Shockwave(_)
285 | CharacterState::Explosion(_)
286 | CharacterState::BasicBeam(_)
287 | CharacterState::BasicAura(_)
288 | CharacterState::StaticAura(_)
289 | CharacterState::Blink(_)
290 | CharacterState::BasicSummon(_)
291 | CharacterState::SelfBuff(_)
292 | CharacterState::SpriteSummon(_)
293 | CharacterState::UseItem(_)
294 | CharacterState::Interact(_)
295 | CharacterState::Wallrun(_)
296 | CharacterState::Skate(_)
297 | CharacterState::Music(_)
298 | CharacterState::FinisherMelee(_)
299 | CharacterState::DiveMelee(_)
300 | CharacterState::RiposteMelee(_)
301 | CharacterState::RapidMelee(_)
302 | CharacterState::Transform(_)
303 | CharacterState::RegrowHead(_) => false,
304 }
305 }
306
307 pub fn was_wielded(&self) -> bool {
308 match self {
309 CharacterState::Roll(data) => data.was_wielded,
310 CharacterState::Stunned(data) => data.was_wielded,
311 CharacterState::Interact(data) => data.static_data.was_wielded,
312 CharacterState::UseItem(data) => data.static_data.was_wielded,
313 CharacterState::Wallrun(data) => data.was_wielded,
314 CharacterState::Climb(data) => data.was_wielded,
315 CharacterState::Idle(_)
316 | CharacterState::Crawl
317 | CharacterState::Sit
318 | CharacterState::Dance
319 | CharacterState::Talk(_)
320 | CharacterState::Glide(_)
321 | CharacterState::GlideWield(_)
322 | CharacterState::BasicBlock(_)
323 | CharacterState::Equipping(_)
324 | CharacterState::Wielding(_)
325 | CharacterState::BasicMelee(_)
326 | CharacterState::BasicRanged(_)
327 | CharacterState::Throw(_)
328 | CharacterState::Boost(_)
329 | CharacterState::DashMelee(_)
330 | CharacterState::ComboMelee2(_)
331 | CharacterState::LeapMelee(_)
332 | CharacterState::LeapShockwave(_)
333 | CharacterState::LeapExplosionShockwave(_)
334 | CharacterState::Explosion(_)
335 | CharacterState::ChargedRanged(_)
336 | CharacterState::ChargedMelee(_)
337 | CharacterState::RepeaterRanged(_)
338 | CharacterState::Shockwave(_)
339 | CharacterState::BasicBeam(_)
340 | CharacterState::BasicAura(_)
341 | CharacterState::StaticAura(_)
342 | CharacterState::Blink(_)
343 | CharacterState::BasicSummon(_)
344 | CharacterState::SelfBuff(_)
345 | CharacterState::SpriteSummon(_)
346 | CharacterState::Skate(_)
347 | CharacterState::Music(_)
348 | CharacterState::FinisherMelee(_)
349 | CharacterState::DiveMelee(_)
350 | CharacterState::RiposteMelee(_)
351 | CharacterState::RapidMelee(_)
352 | CharacterState::Transform(_)
353 | CharacterState::RegrowHead(_) => false,
354 }
355 }
356
357 pub fn is_glide_wielded(&self) -> bool {
358 matches!(
359 self,
360 CharacterState::Glide { .. } | CharacterState::GlideWield { .. }
361 )
362 }
363
364 pub fn is_stealthy(&self) -> bool {
365 matches!(
366 self,
367 CharacterState::Idle(idle::Data {
368 is_sneaking: true,
369 footwear: _,
370 time_entered: _,
371 }) | CharacterState::Wielding(wielding::Data {
372 is_sneaking: true,
373 ..
374 }) | CharacterState::Roll(roll::Data {
375 is_sneaking: true,
376 ..
377 })
378 )
379 }
380
381 pub fn should_follow_look(&self) -> bool {
382 matches!(self, CharacterState::Boost(_)) || self.is_attack()
383 }
384
385 pub fn is_attack(&self) -> bool {
386 matches!(
387 self,
388 CharacterState::BasicMelee(_)
389 | CharacterState::BasicRanged(_)
390 | CharacterState::DashMelee(_)
391 | CharacterState::ComboMelee2(_)
392 | CharacterState::LeapExplosionShockwave(_)
393 | CharacterState::LeapMelee(_)
394 | CharacterState::LeapShockwave(_)
395 | CharacterState::ChargedMelee(_)
396 | CharacterState::ChargedRanged(_)
397 | CharacterState::RepeaterRanged(_)
398 | CharacterState::Throw(_)
399 | CharacterState::Shockwave(_)
400 | CharacterState::Explosion(_)
401 | CharacterState::BasicBeam(_)
402 | CharacterState::BasicAura(_)
403 | CharacterState::SelfBuff(_)
404 | CharacterState::Blink(_)
405 | CharacterState::BasicSummon(_)
406 | CharacterState::SpriteSummon(_)
407 | CharacterState::FinisherMelee(_)
408 | CharacterState::DiveMelee(_)
409 | CharacterState::RiposteMelee(_)
410 | CharacterState::RapidMelee(_)
411 | CharacterState::StaticAura(_)
412 )
413 }
414
415 pub fn is_aimed(&self) -> bool {
416 matches!(
417 self,
418 CharacterState::BasicMelee(_)
419 | CharacterState::BasicRanged(_)
420 | CharacterState::DashMelee(_)
421 | CharacterState::ComboMelee2(_)
422 | CharacterState::BasicBlock(_)
423 | CharacterState::LeapExplosionShockwave(_)
424 | CharacterState::LeapMelee(_)
425 | CharacterState::LeapShockwave(_)
426 | CharacterState::ChargedMelee(_)
427 | CharacterState::ChargedRanged(_)
428 | CharacterState::RepeaterRanged(_)
429 | CharacterState::Throw(_)
430 | CharacterState::Shockwave(_)
431 | CharacterState::BasicBeam(_)
432 | CharacterState::Stunned(_)
433 | CharacterState::Wielding(_)
434 | CharacterState::FinisherMelee(_)
435 | CharacterState::DiveMelee(_)
436 | CharacterState::RiposteMelee(_)
437 | CharacterState::RapidMelee(_)
438 )
439 }
440
441 pub fn is_using_hands(&self) -> bool {
442 matches!(
443 self,
444 CharacterState::Climb(_)
445 | CharacterState::Equipping(_)
446 | CharacterState::Dance
447 | CharacterState::Glide(_)
448 | CharacterState::GlideWield(_)
449 | CharacterState::Talk(_)
450 | CharacterState::Roll(_),
451 )
452 }
453
454 pub fn is_parry(&self, attack_source: AttackSource) -> bool {
455 let melee = matches!(attack_source, AttackSource::Melee);
456 let from_capability_melee = melee
457 && self
458 .ability_info()
459 .map(|a| a.ability_meta.capabilities)
460 .is_some_and(|c| {
461 c.contains(Capability::PARRIES_MELEE)
462 && matches!(
463 self.stage_section(),
464 Some(StageSection::Buildup | StageSection::Action)
465 )
466 });
467 let from_capability = matches!(
468 attack_source,
469 AttackSource::Melee
470 | AttackSource::Projectile
471 | AttackSource::Beam
472 | AttackSource::AirShockwave
473 | AttackSource::Explosion
474 ) && self
475 .ability_info()
476 .map(|a| a.ability_meta.capabilities)
477 .is_some_and(|c| {
478 c.contains(Capability::PARRIES)
479 && matches!(
480 self.stage_section(),
481 Some(StageSection::Buildup | StageSection::Action)
482 )
483 });
484 let from_state = match self {
485 CharacterState::BasicBlock(c) => c.is_parry(attack_source),
486 CharacterState::RiposteMelee(c) => {
487 melee
488 && matches!(
489 c.stage_section,
490 StageSection::Buildup | StageSection::Action
491 )
492 },
493 _ => false,
494 };
495 from_capability_melee || from_capability || from_state
496 }
497
498 pub fn is_block(&self, attack_source: AttackSource) -> bool {
499 match self {
500 CharacterState::BasicBlock(data) => {
501 data.static_data.blocked_attacks.applies(attack_source)
502 && matches!(
503 self.stage_section(),
504 Some(StageSection::Buildup | StageSection::Action)
505 )
506 },
507 _ => self
508 .ability_info()
509 .map(|ability| ability.ability_meta.capabilities)
510 .is_some_and(|capabilities| {
511 capabilities.contains(Capability::BLOCKS)
512 && matches!(
513 self.stage_section(),
514 Some(StageSection::Buildup | StageSection::Action)
515 )
516 && matches!(attack_source, AttackSource::Melee)
517 }),
518 }
519 }
520
521 pub fn block_angle(&self) -> f32 {
523 match self {
524 CharacterState::BasicBlock(c) => c.static_data.max_angle.to_radians(),
525 CharacterState::ComboMelee2(c) => {
526 let strike_data =
527 c.static_data.strikes[c.completed_strikes % c.static_data.strikes.len()];
528 strike_data.melee_constructor.angle.to_radians()
529 },
530 CharacterState::RiposteMelee(c) => c.static_data.melee_constructor.angle.to_radians(),
531 _ => 0.0,
534 }
535 }
536
537 pub fn is_dodge(&self) -> bool {
538 if let CharacterState::Roll(c) = self {
539 matches!(
540 c.stage_section,
541 StageSection::Buildup | StageSection::Movement
542 )
543 } else {
544 false
545 }
546 }
547
548 pub fn is_glide(&self) -> bool { matches!(self, CharacterState::Glide(_)) }
549
550 pub fn is_skate(&self) -> bool { matches!(self, CharacterState::Skate(_)) }
551
552 pub fn is_music(&self) -> bool { matches!(self, CharacterState::Music(_)) }
553
554 pub fn roll_attack_immunities(&self) -> Option<AttackFilters> {
555 if self.is_dodge()
556 && let CharacterState::Roll(c) = self
557 {
558 Some(c.static_data.attack_immunities)
559 } else {
560 None
561 }
562 }
563
564 pub fn is_stunned(&self) -> bool { matches!(self, CharacterState::Stunned(_)) }
565
566 pub fn is_forced_movement(&self) -> bool {
567 matches!(self, CharacterState::ComboMelee2(s) if s.stage_section == StageSection::Action)
568 || matches!(self, CharacterState::DashMelee(s) if s.stage_section == StageSection::Charge)
569 || matches!(self, CharacterState::LeapMelee(s) if s.stage_section == StageSection::Movement)
570 || matches!(self, CharacterState::Roll(s) if s.stage_section == StageSection::Movement)
571 }
572
573 pub fn is_melee_attack(&self) -> bool { self.attack_kind().contains(&AttackSource::Melee) }
574
575 pub fn is_beam_attack(&self) -> bool { self.attack_kind().contains(&AttackSource::Beam) }
576
577 pub fn can_perform_mounted(&self) -> bool {
578 matches!(
579 self,
580 CharacterState::Idle(_)
581 | CharacterState::Sit
582 | CharacterState::Dance
583 | CharacterState::Talk(_)
584 | CharacterState::Stunned(_)
585 | CharacterState::BasicBlock(_)
586 | CharacterState::Equipping(_)
587 | CharacterState::Wielding(_)
588 | CharacterState::BasicMelee(_)
589 | CharacterState::BasicRanged(_)
590 | CharacterState::ComboMelee2(_)
591 | CharacterState::ChargedRanged(_)
592 | CharacterState::RepeaterRanged(_)
593 | CharacterState::Throw(_)
594 | CharacterState::BasicBeam(_)
595 | CharacterState::BasicAura(_)
596 | CharacterState::BasicSummon(_)
597 | CharacterState::SelfBuff(_)
598 | CharacterState::SpriteSummon(_)
599 | CharacterState::UseItem(_)
600 | CharacterState::Interact(_)
601 | CharacterState::Music(_)
602 | CharacterState::RiposteMelee(_)
603 | CharacterState::RapidMelee(_)
604 )
605 }
606
607 pub fn can_look_while_mounted(&self) -> bool {
610 !matches!(
611 self,
612 CharacterState::Idle(_)
613 | CharacterState::Sit
614 | CharacterState::Dance
615 | CharacterState::Talk(_)
616 | CharacterState::Stunned(_)
617 | CharacterState::Equipping(_)
618 | CharacterState::SelfBuff(_)
619 | CharacterState::BasicAura(_)
620 ) && self.can_perform_mounted()
621 }
622
623 pub fn is_sitting(&self) -> bool {
624 use use_item::{Data, ItemUseKind, StaticData};
625 matches!(
626 self,
627 CharacterState::Sit
628 | CharacterState::UseItem(Data {
629 static_data: StaticData {
630 item_kind: ItemUseKind::Consumable(
631 ConsumableKind::ComplexFood | ConsumableKind::Food
632 ),
633 ..
634 },
635 ..
636 })
637 )
638 }
639
640 pub fn same_variant(&self, other: &Self) -> bool {
642 std::mem::discriminant(self) == std::mem::discriminant(other)
644 }
645
646 pub fn behavior(&self, j: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
647 match &self {
648 CharacterState::Idle(data) => data.behavior(j, output_events),
649 CharacterState::Talk(data) => data.behavior(j, output_events),
650 CharacterState::Climb(data) => data.behavior(j, output_events),
651 CharacterState::Wallrun(data) => data.behavior(j, output_events),
652 CharacterState::Glide(data) => data.behavior(j, output_events),
653 CharacterState::GlideWield(data) => data.behavior(j, output_events),
654 CharacterState::Stunned(data) => data.behavior(j, output_events),
655 CharacterState::Sit => sit::Data::behavior(&sit::Data, j, output_events),
656 CharacterState::Crawl => crawl::Data::behavior(&crawl::Data, j, output_events),
657 CharacterState::Dance => dance::Data::behavior(&dance::Data, j, output_events),
658 CharacterState::BasicBlock(data) => data.behavior(j, output_events),
659 CharacterState::Roll(data) => data.behavior(j, output_events),
660 CharacterState::Wielding(data) => data.behavior(j, output_events),
661 CharacterState::Equipping(data) => data.behavior(j, output_events),
662 CharacterState::ComboMelee2(data) => data.behavior(j, output_events),
663 CharacterState::BasicMelee(data) => data.behavior(j, output_events),
664 CharacterState::BasicRanged(data) => data.behavior(j, output_events),
665 CharacterState::Boost(data) => data.behavior(j, output_events),
666 CharacterState::DashMelee(data) => data.behavior(j, output_events),
667 CharacterState::LeapExplosionShockwave(data) => data.behavior(j, output_events),
668 CharacterState::LeapMelee(data) => data.behavior(j, output_events),
669 CharacterState::LeapShockwave(data) => data.behavior(j, output_events),
670 CharacterState::ChargedMelee(data) => data.behavior(j, output_events),
671 CharacterState::ChargedRanged(data) => data.behavior(j, output_events),
672 CharacterState::RepeaterRanged(data) => data.behavior(j, output_events),
673 CharacterState::Throw(data) => data.behavior(j, output_events),
674 CharacterState::Shockwave(data) => data.behavior(j, output_events),
675 CharacterState::Explosion(data) => data.behavior(j, output_events),
676 CharacterState::BasicBeam(data) => data.behavior(j, output_events),
677 CharacterState::BasicAura(data) => data.behavior(j, output_events),
678 CharacterState::Blink(data) => data.behavior(j, output_events),
679 CharacterState::BasicSummon(data) => data.behavior(j, output_events),
680 CharacterState::SelfBuff(data) => data.behavior(j, output_events),
681 CharacterState::SpriteSummon(data) => data.behavior(j, output_events),
682 CharacterState::UseItem(data) => data.behavior(j, output_events),
683 CharacterState::Interact(data) => data.behavior(j, output_events),
684 CharacterState::Skate(data) => data.behavior(j, output_events),
685 CharacterState::Music(data) => data.behavior(j, output_events),
686 CharacterState::FinisherMelee(data) => data.behavior(j, output_events),
687 CharacterState::DiveMelee(data) => data.behavior(j, output_events),
688 CharacterState::RiposteMelee(data) => data.behavior(j, output_events),
689 CharacterState::RapidMelee(data) => data.behavior(j, output_events),
690 CharacterState::Transform(data) => data.behavior(j, output_events),
691 CharacterState::RegrowHead(data) => data.behavior(j, output_events),
692 CharacterState::StaticAura(data) => data.behavior(j, output_events),
693 }
694 }
695
696 pub fn handle_event(
697 &self,
698 j: &JoinData,
699 output_events: &mut OutputEvents,
700 action: ControlAction,
701 ) -> StateUpdate {
702 match &self {
703 CharacterState::Idle(data) => data.handle_event(j, output_events, action),
704 CharacterState::Talk(data) => data.handle_event(j, output_events, action),
705 CharacterState::Climb(data) => data.handle_event(j, output_events, action),
706 CharacterState::Wallrun(data) => data.handle_event(j, output_events, action),
707 CharacterState::Glide(data) => data.handle_event(j, output_events, action),
708 CharacterState::GlideWield(data) => data.handle_event(j, output_events, action),
709 CharacterState::Stunned(data) => data.handle_event(j, output_events, action),
710 CharacterState::Sit => {
711 states::sit::Data::handle_event(&sit::Data, j, output_events, action)
712 },
713 CharacterState::Crawl => {
714 states::crawl::Data::handle_event(&crawl::Data, j, output_events, action)
715 },
716 CharacterState::Dance => {
717 states::dance::Data::handle_event(&dance::Data, j, output_events, action)
718 },
719 CharacterState::BasicBlock(data) => data.handle_event(j, output_events, action),
720 CharacterState::Roll(data) => data.handle_event(j, output_events, action),
721 CharacterState::Wielding(data) => data.handle_event(j, output_events, action),
722 CharacterState::Equipping(data) => data.handle_event(j, output_events, action),
723 CharacterState::ComboMelee2(data) => data.handle_event(j, output_events, action),
724 CharacterState::BasicMelee(data) => data.handle_event(j, output_events, action),
725 CharacterState::BasicRanged(data) => data.handle_event(j, output_events, action),
726 CharacterState::Boost(data) => data.handle_event(j, output_events, action),
727 CharacterState::DashMelee(data) => data.handle_event(j, output_events, action),
728 CharacterState::LeapExplosionShockwave(data) => {
729 data.handle_event(j, output_events, action)
730 },
731 CharacterState::LeapMelee(data) => data.handle_event(j, output_events, action),
732 CharacterState::LeapShockwave(data) => data.handle_event(j, output_events, action),
733 CharacterState::ChargedMelee(data) => data.handle_event(j, output_events, action),
734 CharacterState::ChargedRanged(data) => data.handle_event(j, output_events, action),
735 CharacterState::RepeaterRanged(data) => data.handle_event(j, output_events, action),
736 CharacterState::Throw(data) => data.handle_event(j, output_events, action),
737 CharacterState::Shockwave(data) => data.handle_event(j, output_events, action),
738 CharacterState::Explosion(data) => data.handle_event(j, output_events, action),
739 CharacterState::BasicBeam(data) => data.handle_event(j, output_events, action),
740 CharacterState::BasicAura(data) => data.handle_event(j, output_events, action),
741 CharacterState::Blink(data) => data.handle_event(j, output_events, action),
742 CharacterState::BasicSummon(data) => data.handle_event(j, output_events, action),
743 CharacterState::SelfBuff(data) => data.handle_event(j, output_events, action),
744 CharacterState::SpriteSummon(data) => data.handle_event(j, output_events, action),
745 CharacterState::UseItem(data) => data.handle_event(j, output_events, action),
746 CharacterState::Interact(data) => data.handle_event(j, output_events, action),
747 CharacterState::Skate(data) => data.handle_event(j, output_events, action),
748 CharacterState::Music(data) => data.handle_event(j, output_events, action),
749 CharacterState::FinisherMelee(data) => data.handle_event(j, output_events, action),
750 CharacterState::DiveMelee(data) => data.handle_event(j, output_events, action),
751 CharacterState::RiposteMelee(data) => data.handle_event(j, output_events, action),
752 CharacterState::RapidMelee(data) => data.handle_event(j, output_events, action),
753 CharacterState::Transform(data) => data.handle_event(j, output_events, action),
754 CharacterState::RegrowHead(data) => data.handle_event(j, output_events, action),
755 CharacterState::StaticAura(data) => data.handle_event(j, output_events, action),
756 }
757 }
758
759 pub fn footwear(&self) -> Option<Friction> {
760 match &self {
761 CharacterState::Idle(data) => data.footwear,
762 CharacterState::Skate(data) => Some(data.footwear),
763 _ => None,
764 }
765 }
766
767 pub fn ability_info(&self) -> Option<AbilityInfo> {
768 match &self {
769 CharacterState::Idle(_) => None,
770 CharacterState::Talk(_) => None,
771 CharacterState::Climb(_) => None,
772 CharacterState::Wallrun(_) => None,
773 CharacterState::Skate(_) => None,
774 CharacterState::Glide(_) => None,
775 CharacterState::GlideWield(_) => None,
776 CharacterState::Stunned(_) => None,
777 CharacterState::Sit => None,
778 CharacterState::Crawl => None,
779 CharacterState::Dance => None,
780 CharacterState::BasicBlock(data) => Some(data.static_data.ability_info),
781 CharacterState::Roll(data) => Some(data.static_data.ability_info),
782 CharacterState::Wielding(_) => None,
783 CharacterState::Equipping(_) => None,
784 CharacterState::ComboMelee2(data) => Some(data.static_data.ability_info),
785 CharacterState::BasicMelee(data) => Some(data.static_data.ability_info),
786 CharacterState::BasicRanged(data) => Some(data.static_data.ability_info),
787 CharacterState::Boost(data) => Some(data.static_data.ability_info),
788 CharacterState::DashMelee(data) => Some(data.static_data.ability_info),
789 CharacterState::LeapExplosionShockwave(data) => Some(data.static_data.ability_info),
790 CharacterState::LeapMelee(data) => Some(data.static_data.ability_info),
791 CharacterState::LeapShockwave(data) => Some(data.static_data.ability_info),
792 CharacterState::ChargedMelee(data) => Some(data.static_data.ability_info),
793 CharacterState::ChargedRanged(data) => Some(data.static_data.ability_info),
794 CharacterState::RepeaterRanged(data) => Some(data.static_data.ability_info),
795 CharacterState::Throw(data) => Some(data.static_data.ability_info),
796 CharacterState::Shockwave(data) => Some(data.static_data.ability_info),
797 CharacterState::Explosion(data) => Some(data.static_data.ability_info),
798 CharacterState::BasicBeam(data) => Some(data.static_data.ability_info),
799 CharacterState::BasicAura(data) => Some(data.static_data.ability_info),
800 CharacterState::Blink(data) => Some(data.static_data.ability_info),
801 CharacterState::BasicSummon(data) => Some(data.static_data.ability_info),
802 CharacterState::SelfBuff(data) => Some(data.static_data.ability_info),
803 CharacterState::SpriteSummon(data) => Some(data.static_data.ability_info),
804 CharacterState::UseItem(_) => None,
805 CharacterState::Interact(_) => None,
806 CharacterState::FinisherMelee(data) => Some(data.static_data.ability_info),
807 CharacterState::Music(data) => Some(data.static_data.ability_info),
808 CharacterState::DiveMelee(data) => Some(data.static_data.ability_info),
809 CharacterState::RiposteMelee(data) => Some(data.static_data.ability_info),
810 CharacterState::RapidMelee(data) => Some(data.static_data.ability_info),
811 CharacterState::Transform(data) => Some(data.static_data.ability_info),
812 CharacterState::RegrowHead(data) => Some(data.static_data.ability_info),
813 CharacterState::StaticAura(data) => Some(data.static_data.ability_info),
814 }
815 }
816
817 pub fn stage_section(&self) -> Option<StageSection> {
818 match &self {
819 CharacterState::Idle(_) => None,
820 CharacterState::Talk(_) => None,
821 CharacterState::Climb(_) => None,
822 CharacterState::Wallrun(_) => None,
823 CharacterState::Skate(_) => None,
824 CharacterState::Glide(_) => None,
825 CharacterState::GlideWield(_) => None,
826 CharacterState::Stunned(data) => Some(data.stage_section),
827 CharacterState::Sit => None,
828 CharacterState::Crawl => None,
829 CharacterState::Dance => None,
830 CharacterState::BasicBlock(data) => Some(data.stage_section),
831 CharacterState::Roll(data) => Some(data.stage_section),
832 CharacterState::Equipping(_) => Some(StageSection::Buildup),
833 CharacterState::Wielding(_) => None,
834 CharacterState::ComboMelee2(data) => Some(data.stage_section),
835 CharacterState::BasicMelee(data) => Some(data.stage_section),
836 CharacterState::BasicRanged(data) => Some(data.stage_section),
837 CharacterState::Boost(_) => None,
838 CharacterState::DashMelee(data) => Some(data.stage_section),
839 CharacterState::LeapExplosionShockwave(data) => Some(data.stage_section),
840 CharacterState::LeapMelee(data) => Some(data.stage_section),
841 CharacterState::LeapShockwave(data) => Some(data.stage_section),
842 CharacterState::ChargedMelee(data) => Some(data.stage_section),
843 CharacterState::ChargedRanged(data) => Some(data.stage_section),
844 CharacterState::RepeaterRanged(data) => Some(data.stage_section),
845 CharacterState::Throw(data) => Some(data.stage_section),
846 CharacterState::Shockwave(data) => Some(data.stage_section),
847 CharacterState::Explosion(data) => Some(data.stage_section),
848 CharacterState::BasicBeam(data) => Some(data.stage_section),
849 CharacterState::BasicAura(data) => Some(data.stage_section),
850 CharacterState::Blink(data) => Some(data.stage_section),
851 CharacterState::BasicSummon(data) => Some(data.stage_section),
852 CharacterState::SelfBuff(data) => Some(data.stage_section),
853 CharacterState::SpriteSummon(data) => Some(data.stage_section),
854 CharacterState::UseItem(data) => Some(data.stage_section),
855 CharacterState::Interact(data) => Some(data.stage_section),
856 CharacterState::FinisherMelee(data) => Some(data.stage_section),
857 CharacterState::Music(data) => Some(data.stage_section),
858 CharacterState::DiveMelee(data) => Some(data.stage_section),
859 CharacterState::RiposteMelee(data) => Some(data.stage_section),
860 CharacterState::RapidMelee(data) => Some(data.stage_section),
861 CharacterState::Transform(data) => Some(data.stage_section),
862 CharacterState::RegrowHead(data) => Some(data.stage_section),
863 CharacterState::StaticAura(data) => Some(data.stage_section),
864 }
865 }
866
867 pub fn durations(&self) -> Option<DurationsInfo> {
868 match &self {
869 CharacterState::Idle(_) => None,
870 CharacterState::Talk(_) => None,
871 CharacterState::Climb(_) => None,
872 CharacterState::Wallrun(_) => None,
873 CharacterState::Skate(_) => None,
874 CharacterState::Glide(_) => None,
875 CharacterState::GlideWield(_) => None,
876 CharacterState::Stunned(data) => Some(DurationsInfo {
877 buildup: Some(data.static_data.buildup_duration),
878 recover: Some(data.static_data.recover_duration),
879 ..Default::default()
880 }),
881 CharacterState::Sit => None,
882 CharacterState::Crawl => None,
883 CharacterState::Dance => None,
884 CharacterState::BasicBlock(data) => Some(DurationsInfo {
885 buildup: Some(data.static_data.buildup_duration),
886 recover: Some(data.static_data.recover_duration),
887 ..Default::default()
888 }),
889 CharacterState::Roll(data) => Some(DurationsInfo {
890 buildup: Some(data.static_data.buildup_duration),
891 recover: Some(data.static_data.recover_duration),
892 movement: Some(data.static_data.movement_duration),
893 ..Default::default()
894 }),
895 CharacterState::Wielding(_) => None,
896 CharacterState::Equipping(data) => Some(DurationsInfo {
897 buildup: Some(data.static_data.buildup_duration),
898 ..Default::default()
899 }),
900 CharacterState::ComboMelee2(data) => {
901 let strike = data.strike_data();
902 Some(DurationsInfo {
903 buildup: Some(strike.buildup_duration),
904 action: Some(strike.swing_duration),
905 recover: Some(strike.recover_duration),
906 ..Default::default()
907 })
908 },
909 CharacterState::BasicMelee(data) => Some(DurationsInfo {
910 buildup: Some(data.static_data.buildup_duration),
911 action: Some(data.static_data.swing_duration),
912 recover: Some(data.static_data.recover_duration),
913 ..Default::default()
914 }),
915 CharacterState::BasicRanged(data) => Some(DurationsInfo {
916 buildup: Some(data.static_data.buildup_duration),
917 recover: Some(data.static_data.recover_duration),
918 ..Default::default()
919 }),
920 CharacterState::Boost(data) => Some(DurationsInfo {
921 movement: Some(data.static_data.movement_duration),
922 ..Default::default()
923 }),
924 CharacterState::DashMelee(data) => Some(DurationsInfo {
925 buildup: Some(data.static_data.buildup_duration),
926 action: Some(data.static_data.swing_duration),
927 recover: Some(data.static_data.recover_duration),
928 charge: Some(data.static_data.charge_duration),
929 ..Default::default()
930 }),
931 CharacterState::LeapExplosionShockwave(data) => Some(DurationsInfo {
932 buildup: Some(data.static_data.buildup_duration),
933 action: Some(data.static_data.swing_duration),
934 recover: Some(data.static_data.recover_duration),
935 movement: Some(data.static_data.movement_duration),
936 ..Default::default()
937 }),
938 CharacterState::LeapMelee(data) => Some(DurationsInfo {
939 buildup: Some(data.static_data.buildup_duration),
940 action: Some(data.static_data.swing_duration),
941 recover: Some(data.static_data.recover_duration),
942 movement: Some(data.static_data.movement_duration),
943 ..Default::default()
944 }),
945 CharacterState::LeapShockwave(data) => Some(DurationsInfo {
946 buildup: Some(data.static_data.buildup_duration),
947 action: Some(data.static_data.swing_duration),
948 recover: Some(data.static_data.recover_duration),
949 movement: Some(data.static_data.movement_duration),
950 ..Default::default()
951 }),
952 CharacterState::ChargedMelee(data) => Some(DurationsInfo {
953 buildup: data.static_data.buildup_strike.map(|x| x.0),
954 action: Some(data.static_data.swing_duration),
955 recover: Some(data.static_data.recover_duration),
956 charge: Some(data.static_data.charge_duration),
957 ..Default::default()
958 }),
959 CharacterState::ChargedRanged(data) => Some(DurationsInfo {
960 buildup: Some(data.static_data.buildup_duration),
961 recover: Some(data.static_data.recover_duration),
962 charge: Some(data.static_data.charge_duration),
963 ..Default::default()
964 }),
965 CharacterState::RepeaterRanged(data) => Some(DurationsInfo {
966 buildup: Some(data.static_data.buildup_duration),
967 action: Some(data.static_data.shoot_duration),
968 recover: Some(data.static_data.recover_duration),
969 ..Default::default()
970 }),
971 CharacterState::Throw(data) => Some(DurationsInfo {
972 buildup: Some(data.static_data.buildup_duration),
973 charge: Some(data.static_data.charge_duration),
974 recover: Some(data.static_data.recover_duration),
975 ..Default::default()
976 }),
977 CharacterState::Shockwave(data) => Some(DurationsInfo {
978 buildup: Some(data.static_data.buildup_duration),
979 action: Some(data.static_data.swing_duration),
980 recover: Some(data.static_data.recover_duration),
981 ..Default::default()
982 }),
983 CharacterState::Explosion(data) => Some(DurationsInfo {
984 buildup: Some(data.static_data.buildup_duration),
985 action: Some(data.static_data.action_duration),
986 recover: Some(data.static_data.recover_duration),
987 ..Default::default()
988 }),
989 CharacterState::BasicBeam(data) => Some(DurationsInfo {
990 buildup: Some(data.static_data.buildup_duration),
991 recover: Some(data.static_data.recover_duration),
992 ..Default::default()
993 }),
994 CharacterState::BasicAura(data) => Some(DurationsInfo {
995 buildup: Some(data.static_data.buildup_duration),
996 action: Some(data.static_data.cast_duration),
997 recover: Some(data.static_data.recover_duration),
998 ..Default::default()
999 }),
1000 CharacterState::Blink(data) => Some(DurationsInfo {
1001 buildup: Some(data.static_data.buildup_duration),
1002 recover: Some(data.static_data.recover_duration),
1003 ..Default::default()
1004 }),
1005 CharacterState::BasicSummon(data) => Some(DurationsInfo {
1006 buildup: Some(data.static_data.buildup_duration),
1007 action: Some(data.static_data.cast_duration),
1008 recover: Some(data.static_data.recover_duration),
1009 ..Default::default()
1010 }),
1011 CharacterState::SelfBuff(data) => Some(DurationsInfo {
1012 buildup: Some(data.static_data.buildup_duration),
1013 action: Some(data.static_data.cast_duration),
1014 recover: Some(data.static_data.recover_duration),
1015 ..Default::default()
1016 }),
1017 CharacterState::SpriteSummon(data) => Some(DurationsInfo {
1018 buildup: Some(data.static_data.buildup_duration),
1019 action: Some(data.static_data.cast_duration),
1020 recover: Some(data.static_data.recover_duration),
1021 ..Default::default()
1022 }),
1023 CharacterState::UseItem(data) => Some(DurationsInfo {
1024 buildup: Some(data.static_data.buildup_duration),
1025 action: Some(data.static_data.use_duration),
1026 recover: Some(data.static_data.recover_duration),
1027 ..Default::default()
1028 }),
1029 CharacterState::Interact(data) => Some(DurationsInfo {
1030 buildup: Some(data.static_data.buildup_duration),
1031 action: data.static_data.use_duration,
1032 recover: Some(data.static_data.recover_duration),
1033 ..Default::default()
1034 }),
1035 CharacterState::FinisherMelee(data) => Some(DurationsInfo {
1036 buildup: Some(data.static_data.buildup_duration),
1037 action: Some(data.static_data.swing_duration),
1038 recover: Some(data.static_data.recover_duration),
1039 ..Default::default()
1040 }),
1041 CharacterState::Music(data) => Some(DurationsInfo {
1042 action: Some(data.static_data.play_duration),
1043 ..Default::default()
1044 }),
1045 CharacterState::DiveMelee(data) => Some(DurationsInfo {
1046 buildup: data.static_data.buildup_duration,
1047 movement: Some(data.static_data.movement_duration),
1048 action: Some(data.static_data.swing_duration),
1049 recover: Some(data.static_data.recover_duration),
1050 ..Default::default()
1051 }),
1052 CharacterState::RiposteMelee(data) => Some(DurationsInfo {
1053 buildup: Some(data.static_data.buildup_duration),
1054 action: Some(data.static_data.swing_duration),
1055 recover: Some(if data.whiffed {
1056 data.static_data.whiffed_recover_duration
1057 } else {
1058 data.static_data.recover_duration
1059 }),
1060 ..Default::default()
1061 }),
1062 CharacterState::RapidMelee(data) => Some(DurationsInfo {
1063 buildup: Some(data.static_data.buildup_duration),
1064 action: Some(data.static_data.swing_duration),
1065 recover: Some(data.static_data.recover_duration),
1066 ..Default::default()
1067 }),
1068 CharacterState::Transform(data) => Some(DurationsInfo {
1069 buildup: Some(data.static_data.buildup_duration),
1070 recover: Some(data.static_data.recover_duration),
1071 ..Default::default()
1072 }),
1073 CharacterState::RegrowHead(data) => Some(DurationsInfo {
1074 buildup: Some(data.static_data.buildup_duration),
1075 recover: Some(data.static_data.recover_duration),
1076 ..Default::default()
1077 }),
1078 CharacterState::StaticAura(data) => Some(DurationsInfo {
1079 buildup: Some(data.static_data.buildup_duration),
1080 action: Some(data.static_data.cast_duration),
1081 recover: Some(data.static_data.recover_duration),
1082 ..Default::default()
1083 }),
1084 }
1085 }
1086
1087 pub fn timer(&self) -> Option<Duration> {
1088 match &self {
1089 CharacterState::Idle(_) => None,
1090 CharacterState::Crawl => None,
1091 CharacterState::Talk(_) => None,
1092 CharacterState::Climb(_) => None,
1093 CharacterState::Wallrun(_) => None,
1094 CharacterState::Skate(_) => None,
1095 CharacterState::Glide(data) => Some(data.timer),
1096 CharacterState::GlideWield(_) => None,
1097 CharacterState::Stunned(data) => Some(data.timer),
1098 CharacterState::Sit => None,
1099 CharacterState::Dance => None,
1100 CharacterState::BasicBlock(data) => Some(data.timer),
1101 CharacterState::Roll(data) => Some(data.timer),
1102 CharacterState::Wielding(_) => None,
1103 CharacterState::Equipping(data) => Some(data.timer),
1104 CharacterState::ComboMelee2(data) => Some(data.timer),
1105 CharacterState::BasicMelee(data) => Some(data.timer),
1106 CharacterState::BasicRanged(data) => Some(data.timer),
1107 CharacterState::Boost(data) => Some(data.timer),
1108 CharacterState::DashMelee(data) => Some(data.timer),
1109 CharacterState::LeapExplosionShockwave(data) => Some(data.timer),
1110 CharacterState::LeapMelee(data) => Some(data.timer),
1111 CharacterState::LeapShockwave(data) => Some(data.timer),
1112 CharacterState::ChargedMelee(data) => Some(data.timer),
1113 CharacterState::ChargedRanged(data) => Some(data.timer),
1114 CharacterState::RepeaterRanged(data) => Some(data.timer),
1115 CharacterState::Throw(data) => Some(data.timer),
1116 CharacterState::Shockwave(data) => Some(data.timer),
1117 CharacterState::Explosion(data) => Some(data.timer),
1118 CharacterState::BasicBeam(data) => Some(data.timer),
1119 CharacterState::BasicAura(data) => Some(data.timer),
1120 CharacterState::Blink(data) => Some(data.timer),
1121 CharacterState::BasicSummon(data) => Some(data.timer),
1122 CharacterState::SelfBuff(data) => Some(data.timer),
1123 CharacterState::SpriteSummon(data) => Some(data.timer),
1124 CharacterState::UseItem(data) => Some(data.timer),
1125 CharacterState::Interact(data) => Some(data.timer),
1126 CharacterState::FinisherMelee(data) => Some(data.timer),
1127 CharacterState::Music(data) => Some(data.timer),
1128 CharacterState::DiveMelee(data) => Some(data.timer),
1129 CharacterState::RiposteMelee(data) => Some(data.timer),
1130 CharacterState::RapidMelee(data) => Some(data.timer),
1131 CharacterState::Transform(data) => Some(data.timer),
1132 CharacterState::RegrowHead(data) => Some(data.timer),
1133 CharacterState::StaticAura(data) => Some(data.timer),
1134 }
1135 }
1136
1137 pub fn attack_kind(&self) -> &[AttackSource] {
1138 match self {
1139 CharacterState::Idle(_) => &[],
1140 CharacterState::Crawl => &[],
1141 CharacterState::Talk(_) => &[],
1142 CharacterState::Climb(_) => &[],
1143 CharacterState::Wallrun(_) => &[],
1144 CharacterState::Skate(_) => &[],
1145 CharacterState::Glide(_) => &[],
1146 CharacterState::GlideWield(_) => &[],
1147 CharacterState::Stunned(_) => &[],
1148 CharacterState::Sit => &[],
1149 CharacterState::Dance => &[],
1150 CharacterState::BasicBlock(_) => &[],
1151 CharacterState::Roll(_) => &[],
1152 CharacterState::Wielding(_) => &[],
1153 CharacterState::Equipping(_) => &[],
1154 CharacterState::ComboMelee2(_) => &[AttackSource::Melee],
1155 CharacterState::BasicMelee(_) => &[AttackSource::Melee],
1156 CharacterState::BasicRanged(data) => {
1157 if data.static_data.projectile.is_explosive() {
1158 &[AttackSource::Explosion]
1159 } else {
1160 &[AttackSource::Projectile]
1161 }
1162 },
1163 CharacterState::Boost(_) => &[],
1164 CharacterState::DashMelee(_) => &[AttackSource::Melee],
1165 CharacterState::LeapMelee(_) => &[AttackSource::Melee],
1166 CharacterState::ChargedMelee(_) => &[AttackSource::Melee],
1167 CharacterState::ChargedRanged(_) => &[AttackSource::Projectile],
1169 CharacterState::RepeaterRanged(data) => {
1170 if data.static_data.projectile.is_explosive() {
1171 &[AttackSource::Explosion]
1172 } else {
1173 &[AttackSource::Projectile]
1174 }
1175 },
1176 CharacterState::LeapExplosionShockwave(data) => data
1177 .static_data
1178 .shockwave_dodgeable
1179 .explosion_shockwave_attack_source_slice(),
1180 CharacterState::Throw(_) => &[AttackSource::Projectile],
1181 CharacterState::Shockwave(data) => {
1182 data.static_data.dodgeable.shockwave_attack_source_slice()
1183 },
1184 CharacterState::LeapShockwave(data) => {
1185 data.static_data.dodgeable.shockwave_attack_source_slice()
1186 },
1187 CharacterState::Explosion(_) => &[AttackSource::Explosion],
1188 CharacterState::BasicBeam(_) => &[AttackSource::Beam],
1189 CharacterState::BasicAura(_) => &[],
1190 CharacterState::Blink(_) => &[],
1191 CharacterState::BasicSummon(_) => &[],
1192 CharacterState::SelfBuff(_) => &[],
1193 CharacterState::SpriteSummon(_) => &[],
1194 CharacterState::UseItem(_) => &[],
1195 CharacterState::Interact(_) => &[],
1196 CharacterState::FinisherMelee(_) => &[AttackSource::Melee],
1197 CharacterState::Music(_) => &[],
1198 CharacterState::DiveMelee(_) => &[AttackSource::Melee],
1199 CharacterState::RiposteMelee(_) => &[AttackSource::Melee],
1200 CharacterState::RapidMelee(_) => &[AttackSource::Melee],
1201 CharacterState::Transform(_) => &[],
1202 CharacterState::RegrowHead(_) => &[],
1203 CharacterState::StaticAura(_) => &[],
1204 }
1205 }
1206}
1207
1208#[derive(Default, Copy, Clone)]
1209pub struct DurationsInfo {
1210 pub buildup: Option<Duration>,
1211 pub action: Option<Duration>,
1212 pub recover: Option<Duration>,
1213 pub movement: Option<Duration>,
1214 pub charge: Option<Duration>,
1215}
1216
1217#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq)]
1218pub struct AttackFilters {
1219 pub melee: bool,
1220 pub projectiles: bool,
1221 pub beams: bool,
1222 pub ground_shockwaves: bool,
1223 pub air_shockwaves: bool,
1224 pub explosions: bool,
1225}
1226
1227impl AttackFilters {
1228 pub fn applies(&self, attack: AttackSource) -> bool {
1229 match attack {
1230 AttackSource::Melee => self.melee,
1231 AttackSource::Projectile => self.projectiles,
1232 AttackSource::Beam => self.beams,
1233 AttackSource::GroundShockwave => self.ground_shockwaves,
1234 AttackSource::AirShockwave => self.air_shockwaves,
1235 AttackSource::UndodgeableShockwave => false,
1236 AttackSource::Explosion => self.explosions,
1237 }
1238 }
1239}
1240
1241impl Default for CharacterState {
1242 fn default() -> Self {
1243 Self::Idle(idle::Data {
1244 is_sneaking: false,
1245 footwear: None,
1246 time_entered: Time(0.0),
1247 })
1248 }
1249}
1250
1251impl Component for CharacterState {
1252 type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
1253}
1254
1255#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
1262pub struct CharacterActivity {
1263 pub look_dir: Option<Dir>,
1266 pub steer_dir: f32,
1270 pub is_pet_staying: bool,
1273}
1274
1275impl Component for CharacterActivity {
1276 type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
1277}