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