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