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