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