veloren_common/comp/
character_state.rs

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
23/// Data returned from character behavior fn's to Character Behavior System.
24pub 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        teleport_to: event::TeleportToEvent,
44        shockwave: event::ShockwaveEvent,
45        explosion: event::ExplosionEvent,
46        buff: event::BuffEvent,
47        inventory_manip: event::InventoryManipEvent,
48        sprite_summon: event::CreateSpriteEvent,
49        change_stance: event::ChangeStanceEvent,
50        create_npc: event::CreateNpcEvent,
51        energy_change: event::EnergyChangeEvent,
52        knockback: event::KnockbackEvent,
53        sprite_light: event::ToggleSpriteLightEvent,
54        transform: event::TransformEvent,
55        regrow_head: event::RegrowHeadEvent,
56        create_aura_entity: event::CreateAuraEntityEvent,
57        help_downed: event::HelpDownedEvent,
58    }
59}
60
61pub struct OutputEvents<'a, 'b> {
62    local: &'a mut Vec<LocalEvent>,
63    server: &'a mut CharacterStateEventEmitters<'b>,
64}
65
66impl<'a, 'b: 'a> OutputEvents<'a, 'b> {
67    pub fn new(
68        local: &'a mut Vec<LocalEvent>,
69        server: &'a mut CharacterStateEventEmitters<'b>,
70    ) -> Self {
71        Self { local, server }
72    }
73
74    pub fn emit_local(&mut self, event: LocalEvent) { self.local.push(event); }
75
76    pub fn emit_server<E>(&mut self, event: E)
77    where
78        CharacterStateEventEmitters<'b>: EmitExt<E>,
79    {
80        self.server.emit(event);
81    }
82}
83
84impl From<&JoinData<'_>> for StateUpdate {
85    fn from(data: &JoinData) -> Self {
86        StateUpdate {
87            pos: *data.pos,
88            vel: *data.vel,
89            ori: *data.ori,
90            density: *data.density,
91            energy: *data.energy,
92            swap_equipped_weapons: false,
93            should_strafe: data.inputs.strafing,
94            character: data.character.clone(),
95            queued_inputs: BTreeMap::new(),
96            removed_inputs: Vec::new(),
97            character_activity: data.character_activity.clone(),
98        }
99    }
100}
101#[derive(Clone, Debug, Display, PartialEq, Serialize, Deserialize)]
102pub enum CharacterState {
103    Idle(idle::Data),
104    Crawl,
105    Climb(climb::Data),
106    Sit,
107    Dance,
108    Talk(talk::Data),
109    Glide(glide::Data),
110    GlideWield(glide_wield::Data),
111    /// A stunned state
112    Stunned(stunned::Data),
113    /// A basic blocking state
114    BasicBlock(basic_block::Data),
115    /// Player is busy equipping or unequipping weapons
116    Equipping(equipping::Data),
117    /// Player is holding a weapon and can perform other actions
118    Wielding(wielding::Data),
119    /// A dodge where player can roll
120    Roll(roll::Data),
121    /// A basic melee attack (e.g. sword)
122    BasicMelee(basic_melee::Data),
123    /// A basic ranged attack (e.g. bow)
124    BasicRanged(basic_ranged::Data),
125    /// A force will boost you into a direction for some duration
126    Boost(boost::Data),
127    /// Dash forward and then attack
128    DashMelee(dash_melee::Data),
129    /// A state where you progress through multiple melee attacks
130    ComboMelee2(combo_melee2::Data),
131    /// A leap followed by a small aoe ground attack
132    LeapMelee(leap_melee::Data),
133    /// A leap followed by a shockwave
134    LeapShockwave(leap_shockwave::Data),
135    /// A charged ranged attack (e.g. bow)
136    ChargedRanged(charged_ranged::Data),
137    /// A charged melee attack
138    ChargedMelee(charged_melee::Data),
139    /// A repeating ranged attack
140    RepeaterRanged(repeater_ranged::Data),
141    /// A ground shockwave attack
142    Shockwave(shockwave::Data),
143    /// A continuous attack that affects all creatures in a cone originating
144    /// from the source
145    BasicBeam(basic_beam::Data),
146    /// Creates an aura that persists as long as you are actively casting
147    BasicAura(basic_aura::Data),
148    /// Creates an aura that is attached to a pseudo entity, so it doesn't move
149    /// with you Optionally allows for sprites to be created as well
150    StaticAura(static_aura::Data),
151    /// A short teleport that targets either a position or entity
152    Blink(blink::Data),
153    /// Summons creatures that fight for the caster
154    BasicSummon(basic_summon::Data),
155    /// Inserts a buff on the caster
156    SelfBuff(self_buff::Data),
157    /// Creates sprites around the caster
158    SpriteSummon(sprite_summon::Data),
159    /// Handles logic for using an item so it is not simply instant
160    UseItem(use_item::Data),
161    /// Handles logic for interacting with a sprite or an entity, e.g. using a
162    /// chest, picking a plant, helping a downed entity up
163    Interact(interact::Data),
164    /// Runs on the wall
165    Wallrun(wallrun::Data),
166    /// Ice skating or skiing
167    Skate(skate::Data),
168    /// Play music instrument
169    Music(music::Data),
170    /// Melee attack that scales off and consumes combo
171    FinisherMelee(finisher_melee::Data),
172    /// State entered when diving, melee attack triggered upon landing on the
173    /// ground
174    DiveMelee(dive_melee::Data),
175    /// Attack that attempts to parry, and if it parries moves to an attack
176    RiposteMelee(riposte_melee::Data),
177    /// A series of consecutive, identical attacks that only go through buildup
178    /// and recover once for the entire state
179    RapidMelee(rapid_melee::Data),
180    /// Transforms an entity into another
181    Transform(transform::Data),
182    /// Regrow a missing head
183    RegrowHead(regrow_head::Data),
184}
185
186impl CharacterState {
187    pub fn is_wield(&self) -> bool {
188        matches!(
189            self,
190            CharacterState::Wielding(_)
191                | CharacterState::BasicMelee(_)
192                | CharacterState::BasicRanged(_)
193                | CharacterState::DashMelee(_)
194                | CharacterState::ComboMelee2(_)
195                | CharacterState::BasicBlock(_)
196                | CharacterState::LeapMelee(_)
197                | CharacterState::LeapShockwave(_)
198                | CharacterState::ChargedMelee(_)
199                | CharacterState::ChargedRanged(_)
200                | CharacterState::RepeaterRanged(_)
201                | CharacterState::Shockwave(_)
202                | CharacterState::BasicBeam(_)
203                | CharacterState::BasicAura(_)
204                | CharacterState::SelfBuff(_)
205                | CharacterState::Blink(_)
206                | CharacterState::Music(_)
207                | CharacterState::BasicSummon(_)
208                | CharacterState::SpriteSummon(_)
209                | CharacterState::Roll(roll::Data {
210                    was_wielded: true,
211                    ..
212                })
213                | CharacterState::Wallrun(wallrun::Data { was_wielded: true })
214                | CharacterState::Stunned(stunned::Data {
215                    was_wielded: true,
216                    ..
217                })
218                | CharacterState::FinisherMelee(_)
219                | CharacterState::DiveMelee(_)
220                | CharacterState::RiposteMelee(_)
221                | CharacterState::RapidMelee(_)
222                | CharacterState::StaticAura(_)
223        )
224    }
225
226    /// If this state can manipulate loadout, interact with sprites etc.
227    pub fn can_interact(&self) -> bool {
228        match self {
229            CharacterState::Idle(_)
230            | CharacterState::Sit
231            | CharacterState::Dance
232            | CharacterState::Talk(_)
233            | CharacterState::Equipping(_)
234            | CharacterState::Wielding(_)
235            | CharacterState::GlideWield(_) => true,
236            CharacterState::Crawl
237            | CharacterState::Climb(_)
238            | CharacterState::Glide(_)
239            | CharacterState::Stunned(_)
240            | CharacterState::BasicBlock(_)
241            | CharacterState::Roll(_)
242            | CharacterState::BasicMelee(_)
243            | CharacterState::BasicRanged(_)
244            | CharacterState::Boost(_)
245            | CharacterState::DashMelee(_)
246            | CharacterState::ComboMelee2(_)
247            | CharacterState::LeapMelee(_)
248            | CharacterState::LeapShockwave(_)
249            | CharacterState::ChargedRanged(_)
250            | CharacterState::ChargedMelee(_)
251            | CharacterState::RepeaterRanged(_)
252            | CharacterState::Shockwave(_)
253            | CharacterState::BasicBeam(_)
254            | CharacterState::BasicAura(_)
255            | CharacterState::StaticAura(_)
256            | CharacterState::Blink(_)
257            | CharacterState::BasicSummon(_)
258            | CharacterState::SelfBuff(_)
259            | CharacterState::SpriteSummon(_)
260            | CharacterState::UseItem(_)
261            | CharacterState::Interact(_)
262            | CharacterState::Wallrun(_)
263            | CharacterState::Skate(_)
264            | CharacterState::Music(_)
265            | CharacterState::FinisherMelee(_)
266            | CharacterState::DiveMelee(_)
267            | CharacterState::RiposteMelee(_)
268            | CharacterState::RapidMelee(_)
269            | CharacterState::Transform(_)
270            | CharacterState::RegrowHead(_) => false,
271        }
272    }
273
274    pub fn was_wielded(&self) -> bool {
275        match self {
276            CharacterState::Roll(data) => data.was_wielded,
277            CharacterState::Stunned(data) => data.was_wielded,
278            CharacterState::Interact(data) => data.static_data.was_wielded,
279            CharacterState::UseItem(data) => data.static_data.was_wielded,
280            CharacterState::Wallrun(data) => data.was_wielded,
281            _ => false,
282        }
283    }
284
285    pub fn is_glide_wielded(&self) -> bool {
286        matches!(
287            self,
288            CharacterState::Glide { .. } | CharacterState::GlideWield { .. }
289        )
290    }
291
292    pub fn is_stealthy(&self) -> bool {
293        matches!(
294            self,
295            CharacterState::Idle(idle::Data {
296                is_sneaking: true,
297                footwear: _,
298                time_entered: _,
299            }) | CharacterState::Wielding(wielding::Data {
300                is_sneaking: true,
301                ..
302            }) | CharacterState::Roll(roll::Data {
303                is_sneaking: true,
304                ..
305            })
306        )
307    }
308
309    pub fn should_follow_look(&self) -> bool {
310        matches!(self, CharacterState::Boost(_)) || self.is_attack()
311    }
312
313    pub fn is_attack(&self) -> bool {
314        matches!(
315            self,
316            CharacterState::BasicMelee(_)
317                | CharacterState::BasicRanged(_)
318                | CharacterState::DashMelee(_)
319                | CharacterState::ComboMelee2(_)
320                | CharacterState::LeapMelee(_)
321                | CharacterState::LeapShockwave(_)
322                | CharacterState::ChargedMelee(_)
323                | CharacterState::ChargedRanged(_)
324                | CharacterState::RepeaterRanged(_)
325                | CharacterState::Shockwave(_)
326                | CharacterState::BasicBeam(_)
327                | CharacterState::BasicAura(_)
328                | CharacterState::SelfBuff(_)
329                | CharacterState::Blink(_)
330                | CharacterState::BasicSummon(_)
331                | CharacterState::SpriteSummon(_)
332                | CharacterState::FinisherMelee(_)
333                | CharacterState::DiveMelee(_)
334                | CharacterState::RiposteMelee(_)
335                | CharacterState::RapidMelee(_)
336                | CharacterState::StaticAura(_)
337        )
338    }
339
340    pub fn is_aimed(&self) -> bool {
341        matches!(
342            self,
343            CharacterState::BasicMelee(_)
344                | CharacterState::BasicRanged(_)
345                | CharacterState::DashMelee(_)
346                | CharacterState::ComboMelee2(_)
347                | CharacterState::BasicBlock(_)
348                | CharacterState::LeapMelee(_)
349                | CharacterState::LeapShockwave(_)
350                | CharacterState::ChargedMelee(_)
351                | CharacterState::ChargedRanged(_)
352                | CharacterState::RepeaterRanged(_)
353                | CharacterState::Shockwave(_)
354                | CharacterState::BasicBeam(_)
355                | CharacterState::Stunned(_)
356                | CharacterState::Wielding(_)
357                | CharacterState::Talk(_)
358                | CharacterState::FinisherMelee(_)
359                | CharacterState::DiveMelee(_)
360                | CharacterState::RiposteMelee(_)
361                | CharacterState::RapidMelee(_)
362        )
363    }
364
365    pub fn is_using_hands(&self) -> bool {
366        matches!(
367            self,
368            CharacterState::Climb(_)
369                | CharacterState::Equipping(_)
370                | CharacterState::Dance
371                | CharacterState::Glide(_)
372                | CharacterState::GlideWield(_)
373                | CharacterState::Talk(_)
374                | CharacterState::Roll(_),
375        )
376    }
377
378    pub fn is_parry(&self, attack_source: AttackSource) -> bool {
379        let melee = matches!(attack_source, AttackSource::Melee);
380        let from_capability_melee = melee
381            && self
382                .ability_info()
383                .map(|a| a.ability_meta.capabilities)
384                .is_some_and(|c| {
385                    c.contains(Capability::PARRIES_MELEE)
386                        && matches!(
387                            self.stage_section(),
388                            Some(StageSection::Buildup | StageSection::Action)
389                        )
390                });
391        let from_capability = matches!(
392            attack_source,
393            AttackSource::Melee
394                | AttackSource::Projectile
395                | AttackSource::Beam
396                | AttackSource::AirShockwave
397                | AttackSource::Explosion
398        ) && self
399            .ability_info()
400            .map(|a| a.ability_meta.capabilities)
401            .is_some_and(|c| {
402                c.contains(Capability::PARRIES)
403                    && matches!(
404                        self.stage_section(),
405                        Some(StageSection::Buildup | StageSection::Action)
406                    )
407            });
408        let from_state = match self {
409            CharacterState::BasicBlock(c) => c.is_parry(attack_source),
410            CharacterState::RiposteMelee(c) => {
411                melee
412                    && matches!(
413                        c.stage_section,
414                        StageSection::Buildup | StageSection::Action
415                    )
416            },
417            _ => false,
418        };
419        from_capability_melee || from_capability || from_state
420    }
421
422    pub fn is_block(&self, attack_source: AttackSource) -> bool {
423        match self {
424            CharacterState::BasicBlock(data) => {
425                data.static_data.blocked_attacks.applies(attack_source)
426                    && matches!(
427                        self.stage_section(),
428                        Some(StageSection::Buildup | StageSection::Action)
429                    )
430            },
431            _ => self
432                .ability_info()
433                .map(|ability| ability.ability_meta.capabilities)
434                .is_some_and(|capabilities| {
435                    capabilities.contains(Capability::BLOCKS)
436                        && matches!(
437                            self.stage_section(),
438                            Some(StageSection::Buildup | StageSection::Action)
439                        )
440                        && matches!(attack_source, AttackSource::Melee)
441                }),
442        }
443    }
444
445    /// In radians
446    pub fn block_angle(&self) -> f32 {
447        match self {
448            CharacterState::BasicBlock(c) => c.static_data.max_angle.to_radians(),
449            CharacterState::ComboMelee2(c) => {
450                let strike_data =
451                    c.static_data.strikes[c.completed_strikes % c.static_data.strikes.len()];
452                strike_data.melee_constructor.angle.to_radians()
453            },
454            CharacterState::RiposteMelee(c) => c.static_data.melee_constructor.angle.to_radians(),
455            // TODO: Add more here as needed, maybe look into having character state return the
456            // melee constructor if it has one and using that?
457            _ => 0.0,
458        }
459    }
460
461    pub fn is_dodge(&self) -> bool {
462        if let CharacterState::Roll(c) = self {
463            matches!(
464                c.stage_section,
465                StageSection::Buildup | StageSection::Movement
466            )
467        } else {
468            false
469        }
470    }
471
472    pub fn is_glide(&self) -> bool { matches!(self, CharacterState::Glide(_)) }
473
474    pub fn is_skate(&self) -> bool { matches!(self, CharacterState::Skate(_)) }
475
476    pub fn is_music(&self) -> bool { matches!(self, CharacterState::Music(_)) }
477
478    pub fn roll_attack_immunities(&self) -> Option<AttackFilters> {
479        if self.is_dodge()
480            && let CharacterState::Roll(c) = self
481        {
482            Some(c.static_data.attack_immunities)
483        } else {
484            None
485        }
486    }
487
488    pub fn is_stunned(&self) -> bool { matches!(self, CharacterState::Stunned(_)) }
489
490    pub fn is_forced_movement(&self) -> bool {
491        matches!(self, CharacterState::ComboMelee2(s) if s.stage_section == StageSection::Action)
492            || matches!(self, CharacterState::DashMelee(s) if s.stage_section == StageSection::Charge)
493            || matches!(self, CharacterState::LeapMelee(s) if s.stage_section == StageSection::Movement)
494            || matches!(self, CharacterState::Roll(s) if s.stage_section == StageSection::Movement)
495    }
496
497    pub fn is_melee_attack(&self) -> bool {
498        matches!(self.attack_kind(), Some(AttackSource::Melee))
499    }
500
501    pub fn is_beam_attack(&self) -> bool { matches!(self.attack_kind(), Some(AttackSource::Beam)) }
502
503    pub fn can_perform_mounted(&self) -> bool {
504        matches!(
505            self,
506            CharacterState::Idle(_)
507                | CharacterState::Sit
508                | CharacterState::Dance
509                | CharacterState::Talk(_)
510                | CharacterState::Stunned(_)
511                | CharacterState::BasicBlock(_)
512                | CharacterState::Equipping(_)
513                | CharacterState::Wielding(_)
514                | CharacterState::BasicMelee(_)
515                | CharacterState::BasicRanged(_)
516                | CharacterState::ComboMelee2(_)
517                | CharacterState::ChargedRanged(_)
518                | CharacterState::RepeaterRanged(_)
519                | CharacterState::BasicBeam(_)
520                | CharacterState::BasicAura(_)
521                | CharacterState::BasicSummon(_)
522                | CharacterState::SelfBuff(_)
523                | CharacterState::SpriteSummon(_)
524                | CharacterState::UseItem(_)
525                | CharacterState::Interact(_)
526                | CharacterState::Music(_)
527                | CharacterState::RiposteMelee(_)
528                | CharacterState::RapidMelee(_)
529        )
530    }
531
532    pub fn is_sitting(&self) -> bool {
533        use use_item::{Data, ItemUseKind, StaticData};
534        matches!(
535            self,
536            CharacterState::Sit
537                | CharacterState::UseItem(Data {
538                    static_data: StaticData {
539                        item_kind: ItemUseKind::Consumable(
540                            ConsumableKind::ComplexFood | ConsumableKind::Food
541                        ),
542                        ..
543                    },
544                    ..
545                })
546        )
547    }
548
549    /// Compares for shallow equality (does not check internal struct equality)
550    pub fn same_variant(&self, other: &Self) -> bool {
551        // Check if state is the same without looking at the inner data
552        std::mem::discriminant(self) == std::mem::discriminant(other)
553    }
554
555    pub fn behavior(&self, j: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
556        match &self {
557            CharacterState::Idle(data) => data.behavior(j, output_events),
558            CharacterState::Talk(data) => data.behavior(j, output_events),
559            CharacterState::Climb(data) => data.behavior(j, output_events),
560            CharacterState::Wallrun(data) => data.behavior(j, output_events),
561            CharacterState::Glide(data) => data.behavior(j, output_events),
562            CharacterState::GlideWield(data) => data.behavior(j, output_events),
563            CharacterState::Stunned(data) => data.behavior(j, output_events),
564            CharacterState::Sit => sit::Data::behavior(&sit::Data, j, output_events),
565            CharacterState::Crawl => crawl::Data::behavior(&crawl::Data, j, output_events),
566            CharacterState::Dance => dance::Data::behavior(&dance::Data, j, output_events),
567            CharacterState::BasicBlock(data) => data.behavior(j, output_events),
568            CharacterState::Roll(data) => data.behavior(j, output_events),
569            CharacterState::Wielding(data) => data.behavior(j, output_events),
570            CharacterState::Equipping(data) => data.behavior(j, output_events),
571            CharacterState::ComboMelee2(data) => data.behavior(j, output_events),
572            CharacterState::BasicMelee(data) => data.behavior(j, output_events),
573            CharacterState::BasicRanged(data) => data.behavior(j, output_events),
574            CharacterState::Boost(data) => data.behavior(j, output_events),
575            CharacterState::DashMelee(data) => data.behavior(j, output_events),
576            CharacterState::LeapMelee(data) => data.behavior(j, output_events),
577            CharacterState::LeapShockwave(data) => data.behavior(j, output_events),
578            CharacterState::ChargedMelee(data) => data.behavior(j, output_events),
579            CharacterState::ChargedRanged(data) => data.behavior(j, output_events),
580            CharacterState::RepeaterRanged(data) => data.behavior(j, output_events),
581            CharacterState::Shockwave(data) => data.behavior(j, output_events),
582            CharacterState::BasicBeam(data) => data.behavior(j, output_events),
583            CharacterState::BasicAura(data) => data.behavior(j, output_events),
584            CharacterState::Blink(data) => data.behavior(j, output_events),
585            CharacterState::BasicSummon(data) => data.behavior(j, output_events),
586            CharacterState::SelfBuff(data) => data.behavior(j, output_events),
587            CharacterState::SpriteSummon(data) => data.behavior(j, output_events),
588            CharacterState::UseItem(data) => data.behavior(j, output_events),
589            CharacterState::Interact(data) => data.behavior(j, output_events),
590            CharacterState::Skate(data) => data.behavior(j, output_events),
591            CharacterState::Music(data) => data.behavior(j, output_events),
592            CharacterState::FinisherMelee(data) => data.behavior(j, output_events),
593            CharacterState::DiveMelee(data) => data.behavior(j, output_events),
594            CharacterState::RiposteMelee(data) => data.behavior(j, output_events),
595            CharacterState::RapidMelee(data) => data.behavior(j, output_events),
596            CharacterState::Transform(data) => data.behavior(j, output_events),
597            CharacterState::RegrowHead(data) => data.behavior(j, output_events),
598            CharacterState::StaticAura(data) => data.behavior(j, output_events),
599        }
600    }
601
602    pub fn handle_event(
603        &self,
604        j: &JoinData,
605        output_events: &mut OutputEvents,
606        action: ControlAction,
607    ) -> StateUpdate {
608        match &self {
609            CharacterState::Idle(data) => data.handle_event(j, output_events, action),
610            CharacterState::Talk(data) => data.handle_event(j, output_events, action),
611            CharacterState::Climb(data) => data.handle_event(j, output_events, action),
612            CharacterState::Wallrun(data) => data.handle_event(j, output_events, action),
613            CharacterState::Glide(data) => data.handle_event(j, output_events, action),
614            CharacterState::GlideWield(data) => data.handle_event(j, output_events, action),
615            CharacterState::Stunned(data) => data.handle_event(j, output_events, action),
616            CharacterState::Sit => {
617                states::sit::Data::handle_event(&sit::Data, j, output_events, action)
618            },
619            CharacterState::Crawl => {
620                states::crawl::Data::handle_event(&crawl::Data, j, output_events, action)
621            },
622            CharacterState::Dance => {
623                states::dance::Data::handle_event(&dance::Data, j, output_events, action)
624            },
625            CharacterState::BasicBlock(data) => data.handle_event(j, output_events, action),
626            CharacterState::Roll(data) => data.handle_event(j, output_events, action),
627            CharacterState::Wielding(data) => data.handle_event(j, output_events, action),
628            CharacterState::Equipping(data) => data.handle_event(j, output_events, action),
629            CharacterState::ComboMelee2(data) => data.handle_event(j, output_events, action),
630            CharacterState::BasicMelee(data) => data.handle_event(j, output_events, action),
631            CharacterState::BasicRanged(data) => data.handle_event(j, output_events, action),
632            CharacterState::Boost(data) => data.handle_event(j, output_events, action),
633            CharacterState::DashMelee(data) => data.handle_event(j, output_events, action),
634            CharacterState::LeapMelee(data) => data.handle_event(j, output_events, action),
635            CharacterState::LeapShockwave(data) => data.handle_event(j, output_events, action),
636            CharacterState::ChargedMelee(data) => data.handle_event(j, output_events, action),
637            CharacterState::ChargedRanged(data) => data.handle_event(j, output_events, action),
638            CharacterState::RepeaterRanged(data) => data.handle_event(j, output_events, action),
639            CharacterState::Shockwave(data) => data.handle_event(j, output_events, action),
640            CharacterState::BasicBeam(data) => data.handle_event(j, output_events, action),
641            CharacterState::BasicAura(data) => data.handle_event(j, output_events, action),
642            CharacterState::Blink(data) => data.handle_event(j, output_events, action),
643            CharacterState::BasicSummon(data) => data.handle_event(j, output_events, action),
644            CharacterState::SelfBuff(data) => data.handle_event(j, output_events, action),
645            CharacterState::SpriteSummon(data) => data.handle_event(j, output_events, action),
646            CharacterState::UseItem(data) => data.handle_event(j, output_events, action),
647            CharacterState::Interact(data) => data.handle_event(j, output_events, action),
648            CharacterState::Skate(data) => data.handle_event(j, output_events, action),
649            CharacterState::Music(data) => data.handle_event(j, output_events, action),
650            CharacterState::FinisherMelee(data) => data.handle_event(j, output_events, action),
651            CharacterState::DiveMelee(data) => data.handle_event(j, output_events, action),
652            CharacterState::RiposteMelee(data) => data.handle_event(j, output_events, action),
653            CharacterState::RapidMelee(data) => data.handle_event(j, output_events, action),
654            CharacterState::Transform(data) => data.handle_event(j, output_events, action),
655            CharacterState::RegrowHead(data) => data.handle_event(j, output_events, action),
656            CharacterState::StaticAura(data) => data.handle_event(j, output_events, action),
657        }
658    }
659
660    pub fn footwear(&self) -> Option<Friction> {
661        match &self {
662            CharacterState::Idle(data) => data.footwear,
663            CharacterState::Skate(data) => Some(data.footwear),
664            _ => None,
665        }
666    }
667
668    pub fn ability_info(&self) -> Option<AbilityInfo> {
669        match &self {
670            CharacterState::Idle(_) => None,
671            CharacterState::Talk(_) => None,
672            CharacterState::Climb(_) => None,
673            CharacterState::Wallrun(_) => None,
674            CharacterState::Skate(_) => None,
675            CharacterState::Glide(_) => None,
676            CharacterState::GlideWield(_) => None,
677            CharacterState::Stunned(_) => None,
678            CharacterState::Sit => None,
679            CharacterState::Crawl => None,
680            CharacterState::Dance => None,
681            CharacterState::BasicBlock(data) => Some(data.static_data.ability_info),
682            CharacterState::Roll(data) => Some(data.static_data.ability_info),
683            CharacterState::Wielding(_) => None,
684            CharacterState::Equipping(_) => None,
685            CharacterState::ComboMelee2(data) => Some(data.static_data.ability_info),
686            CharacterState::BasicMelee(data) => Some(data.static_data.ability_info),
687            CharacterState::BasicRanged(data) => Some(data.static_data.ability_info),
688            CharacterState::Boost(data) => Some(data.static_data.ability_info),
689            CharacterState::DashMelee(data) => Some(data.static_data.ability_info),
690            CharacterState::LeapMelee(data) => Some(data.static_data.ability_info),
691            CharacterState::LeapShockwave(data) => Some(data.static_data.ability_info),
692            CharacterState::ChargedMelee(data) => Some(data.static_data.ability_info),
693            CharacterState::ChargedRanged(data) => Some(data.static_data.ability_info),
694            CharacterState::RepeaterRanged(data) => Some(data.static_data.ability_info),
695            CharacterState::Shockwave(data) => Some(data.static_data.ability_info),
696            CharacterState::BasicBeam(data) => Some(data.static_data.ability_info),
697            CharacterState::BasicAura(data) => Some(data.static_data.ability_info),
698            CharacterState::Blink(data) => Some(data.static_data.ability_info),
699            CharacterState::BasicSummon(data) => Some(data.static_data.ability_info),
700            CharacterState::SelfBuff(data) => Some(data.static_data.ability_info),
701            CharacterState::SpriteSummon(data) => Some(data.static_data.ability_info),
702            CharacterState::UseItem(_) => None,
703            CharacterState::Interact(_) => None,
704            CharacterState::FinisherMelee(data) => Some(data.static_data.ability_info),
705            CharacterState::Music(data) => Some(data.static_data.ability_info),
706            CharacterState::DiveMelee(data) => Some(data.static_data.ability_info),
707            CharacterState::RiposteMelee(data) => Some(data.static_data.ability_info),
708            CharacterState::RapidMelee(data) => Some(data.static_data.ability_info),
709            CharacterState::Transform(data) => Some(data.static_data.ability_info),
710            CharacterState::RegrowHead(data) => Some(data.static_data.ability_info),
711            CharacterState::StaticAura(data) => Some(data.static_data.ability_info),
712        }
713    }
714
715    pub fn stage_section(&self) -> Option<StageSection> {
716        match &self {
717            CharacterState::Idle(_) => None,
718            CharacterState::Talk(_) => None,
719            CharacterState::Climb(_) => None,
720            CharacterState::Wallrun(_) => None,
721            CharacterState::Skate(_) => None,
722            CharacterState::Glide(_) => None,
723            CharacterState::GlideWield(_) => None,
724            CharacterState::Stunned(data) => Some(data.stage_section),
725            CharacterState::Sit => None,
726            CharacterState::Crawl => None,
727            CharacterState::Dance => None,
728            CharacterState::BasicBlock(data) => Some(data.stage_section),
729            CharacterState::Roll(data) => Some(data.stage_section),
730            CharacterState::Equipping(_) => Some(StageSection::Buildup),
731            CharacterState::Wielding(_) => None,
732            CharacterState::ComboMelee2(data) => Some(data.stage_section),
733            CharacterState::BasicMelee(data) => Some(data.stage_section),
734            CharacterState::BasicRanged(data) => Some(data.stage_section),
735            CharacterState::Boost(_) => None,
736            CharacterState::DashMelee(data) => Some(data.stage_section),
737            CharacterState::LeapMelee(data) => Some(data.stage_section),
738            CharacterState::LeapShockwave(data) => Some(data.stage_section),
739            CharacterState::ChargedMelee(data) => Some(data.stage_section),
740            CharacterState::ChargedRanged(data) => Some(data.stage_section),
741            CharacterState::RepeaterRanged(data) => Some(data.stage_section),
742            CharacterState::Shockwave(data) => Some(data.stage_section),
743            CharacterState::BasicBeam(data) => Some(data.stage_section),
744            CharacterState::BasicAura(data) => Some(data.stage_section),
745            CharacterState::Blink(data) => Some(data.stage_section),
746            CharacterState::BasicSummon(data) => Some(data.stage_section),
747            CharacterState::SelfBuff(data) => Some(data.stage_section),
748            CharacterState::SpriteSummon(data) => Some(data.stage_section),
749            CharacterState::UseItem(data) => Some(data.stage_section),
750            CharacterState::Interact(data) => Some(data.stage_section),
751            CharacterState::FinisherMelee(data) => Some(data.stage_section),
752            CharacterState::Music(data) => Some(data.stage_section),
753            CharacterState::DiveMelee(data) => Some(data.stage_section),
754            CharacterState::RiposteMelee(data) => Some(data.stage_section),
755            CharacterState::RapidMelee(data) => Some(data.stage_section),
756            CharacterState::Transform(data) => Some(data.stage_section),
757            CharacterState::RegrowHead(data) => Some(data.stage_section),
758            CharacterState::StaticAura(data) => Some(data.stage_section),
759        }
760    }
761
762    pub fn durations(&self) -> Option<DurationsInfo> {
763        match &self {
764            CharacterState::Idle(_) => None,
765            CharacterState::Talk(_) => None,
766            CharacterState::Climb(_) => None,
767            CharacterState::Wallrun(_) => None,
768            CharacterState::Skate(_) => None,
769            CharacterState::Glide(_) => None,
770            CharacterState::GlideWield(_) => None,
771            CharacterState::Stunned(data) => Some(DurationsInfo {
772                buildup: Some(data.static_data.buildup_duration),
773                recover: Some(data.static_data.recover_duration),
774                ..Default::default()
775            }),
776            CharacterState::Sit => None,
777            CharacterState::Crawl => None,
778            CharacterState::Dance => None,
779            CharacterState::BasicBlock(data) => Some(DurationsInfo {
780                buildup: Some(data.static_data.buildup_duration),
781                recover: Some(data.static_data.recover_duration),
782                ..Default::default()
783            }),
784            CharacterState::Roll(data) => Some(DurationsInfo {
785                buildup: Some(data.static_data.buildup_duration),
786                recover: Some(data.static_data.recover_duration),
787                movement: Some(data.static_data.movement_duration),
788                ..Default::default()
789            }),
790            CharacterState::Wielding(_) => None,
791            CharacterState::Equipping(data) => Some(DurationsInfo {
792                buildup: Some(data.static_data.buildup_duration),
793                ..Default::default()
794            }),
795            CharacterState::ComboMelee2(data) => {
796                let strike = data.strike_data();
797                Some(DurationsInfo {
798                    buildup: Some(strike.buildup_duration),
799                    action: Some(strike.swing_duration),
800                    recover: Some(strike.recover_duration),
801                    ..Default::default()
802                })
803            },
804            CharacterState::BasicMelee(data) => Some(DurationsInfo {
805                buildup: Some(data.static_data.buildup_duration),
806                action: Some(data.static_data.swing_duration),
807                recover: Some(data.static_data.recover_duration),
808                ..Default::default()
809            }),
810            CharacterState::BasicRanged(data) => Some(DurationsInfo {
811                buildup: Some(data.static_data.buildup_duration),
812                recover: Some(data.static_data.recover_duration),
813                ..Default::default()
814            }),
815            CharacterState::Boost(data) => Some(DurationsInfo {
816                movement: Some(data.static_data.movement_duration),
817                ..Default::default()
818            }),
819            CharacterState::DashMelee(data) => Some(DurationsInfo {
820                buildup: Some(data.static_data.buildup_duration),
821                action: Some(data.static_data.swing_duration),
822                recover: Some(data.static_data.recover_duration),
823                charge: Some(data.static_data.charge_duration),
824                ..Default::default()
825            }),
826            CharacterState::LeapMelee(data) => Some(DurationsInfo {
827                buildup: Some(data.static_data.buildup_duration),
828                action: Some(data.static_data.swing_duration),
829                recover: Some(data.static_data.recover_duration),
830                movement: Some(data.static_data.movement_duration),
831                ..Default::default()
832            }),
833            CharacterState::LeapShockwave(data) => Some(DurationsInfo {
834                buildup: Some(data.static_data.buildup_duration),
835                action: Some(data.static_data.swing_duration),
836                recover: Some(data.static_data.recover_duration),
837                movement: Some(data.static_data.movement_duration),
838                ..Default::default()
839            }),
840            CharacterState::ChargedMelee(data) => Some(DurationsInfo {
841                buildup: data.static_data.buildup_strike.map(|x| x.0),
842                action: Some(data.static_data.swing_duration),
843                recover: Some(data.static_data.recover_duration),
844                charge: Some(data.static_data.charge_duration),
845                ..Default::default()
846            }),
847            CharacterState::ChargedRanged(data) => Some(DurationsInfo {
848                buildup: Some(data.static_data.buildup_duration),
849                recover: Some(data.static_data.recover_duration),
850                charge: Some(data.static_data.charge_duration),
851                ..Default::default()
852            }),
853            CharacterState::RepeaterRanged(data) => Some(DurationsInfo {
854                buildup: Some(data.static_data.buildup_duration),
855                action: Some(data.static_data.shoot_duration),
856                recover: Some(data.static_data.recover_duration),
857                ..Default::default()
858            }),
859            CharacterState::Shockwave(data) => Some(DurationsInfo {
860                buildup: Some(data.static_data.buildup_duration),
861                action: Some(data.static_data.swing_duration),
862                recover: Some(data.static_data.recover_duration),
863                ..Default::default()
864            }),
865            CharacterState::BasicBeam(data) => Some(DurationsInfo {
866                buildup: Some(data.static_data.buildup_duration),
867                recover: Some(data.static_data.recover_duration),
868                ..Default::default()
869            }),
870            CharacterState::BasicAura(data) => Some(DurationsInfo {
871                buildup: Some(data.static_data.buildup_duration),
872                action: Some(data.static_data.cast_duration),
873                recover: Some(data.static_data.recover_duration),
874                ..Default::default()
875            }),
876            CharacterState::Blink(data) => Some(DurationsInfo {
877                buildup: Some(data.static_data.buildup_duration),
878                recover: Some(data.static_data.recover_duration),
879                ..Default::default()
880            }),
881            CharacterState::BasicSummon(data) => Some(DurationsInfo {
882                buildup: Some(data.static_data.buildup_duration),
883                action: Some(data.static_data.cast_duration),
884                recover: Some(data.static_data.recover_duration),
885                ..Default::default()
886            }),
887            CharacterState::SelfBuff(data) => Some(DurationsInfo {
888                buildup: Some(data.static_data.buildup_duration),
889                action: Some(data.static_data.cast_duration),
890                recover: Some(data.static_data.recover_duration),
891                ..Default::default()
892            }),
893            CharacterState::SpriteSummon(data) => Some(DurationsInfo {
894                buildup: Some(data.static_data.buildup_duration),
895                action: Some(data.static_data.cast_duration),
896                recover: Some(data.static_data.recover_duration),
897                ..Default::default()
898            }),
899            CharacterState::UseItem(data) => Some(DurationsInfo {
900                buildup: Some(data.static_data.buildup_duration),
901                action: Some(data.static_data.use_duration),
902                recover: Some(data.static_data.recover_duration),
903                ..Default::default()
904            }),
905            CharacterState::Interact(data) => Some(DurationsInfo {
906                buildup: Some(data.static_data.buildup_duration),
907                action: data.static_data.use_duration,
908                recover: Some(data.static_data.recover_duration),
909                ..Default::default()
910            }),
911            CharacterState::FinisherMelee(data) => Some(DurationsInfo {
912                buildup: Some(data.static_data.buildup_duration),
913                action: Some(data.static_data.swing_duration),
914                recover: Some(data.static_data.recover_duration),
915                ..Default::default()
916            }),
917            CharacterState::Music(data) => Some(DurationsInfo {
918                action: Some(data.static_data.play_duration),
919                ..Default::default()
920            }),
921            CharacterState::DiveMelee(data) => Some(DurationsInfo {
922                action: Some(data.static_data.swing_duration),
923                recover: Some(data.static_data.recover_duration),
924                movement: Some(data.static_data.movement_duration),
925                ..Default::default()
926            }),
927            CharacterState::RiposteMelee(data) => Some(DurationsInfo {
928                buildup: Some(data.static_data.buildup_duration),
929                action: Some(data.static_data.swing_duration),
930                recover: Some(if data.whiffed {
931                    data.static_data.whiffed_recover_duration
932                } else {
933                    data.static_data.recover_duration
934                }),
935                ..Default::default()
936            }),
937            CharacterState::RapidMelee(data) => Some(DurationsInfo {
938                buildup: Some(data.static_data.buildup_duration),
939                action: Some(data.static_data.swing_duration),
940                recover: Some(data.static_data.recover_duration),
941                ..Default::default()
942            }),
943            CharacterState::Transform(data) => Some(DurationsInfo {
944                buildup: Some(data.static_data.buildup_duration),
945                recover: Some(data.static_data.recover_duration),
946                ..Default::default()
947            }),
948            CharacterState::RegrowHead(data) => Some(DurationsInfo {
949                buildup: Some(data.static_data.buildup_duration),
950                recover: Some(data.static_data.recover_duration),
951                ..Default::default()
952            }),
953            CharacterState::StaticAura(data) => Some(DurationsInfo {
954                buildup: Some(data.static_data.buildup_duration),
955                action: Some(data.static_data.cast_duration),
956                recover: Some(data.static_data.recover_duration),
957                ..Default::default()
958            }),
959        }
960    }
961
962    pub fn timer(&self) -> Option<Duration> {
963        match &self {
964            CharacterState::Idle(_) => None,
965            CharacterState::Crawl => None,
966            CharacterState::Talk(_) => None,
967            CharacterState::Climb(_) => None,
968            CharacterState::Wallrun(_) => None,
969            CharacterState::Skate(_) => None,
970            CharacterState::Glide(data) => Some(data.timer),
971            CharacterState::GlideWield(_) => None,
972            CharacterState::Stunned(data) => Some(data.timer),
973            CharacterState::Sit => None,
974            CharacterState::Dance => None,
975            CharacterState::BasicBlock(data) => Some(data.timer),
976            CharacterState::Roll(data) => Some(data.timer),
977            CharacterState::Wielding(_) => None,
978            CharacterState::Equipping(data) => Some(data.timer),
979            CharacterState::ComboMelee2(data) => Some(data.timer),
980            CharacterState::BasicMelee(data) => Some(data.timer),
981            CharacterState::BasicRanged(data) => Some(data.timer),
982            CharacterState::Boost(data) => Some(data.timer),
983            CharacterState::DashMelee(data) => Some(data.timer),
984            CharacterState::LeapMelee(data) => Some(data.timer),
985            CharacterState::LeapShockwave(data) => Some(data.timer),
986            CharacterState::ChargedMelee(data) => Some(data.timer),
987            CharacterState::ChargedRanged(data) => Some(data.timer),
988            CharacterState::RepeaterRanged(data) => Some(data.timer),
989            CharacterState::Shockwave(data) => Some(data.timer),
990            CharacterState::BasicBeam(data) => Some(data.timer),
991            CharacterState::BasicAura(data) => Some(data.timer),
992            CharacterState::Blink(data) => Some(data.timer),
993            CharacterState::BasicSummon(data) => Some(data.timer),
994            CharacterState::SelfBuff(data) => Some(data.timer),
995            CharacterState::SpriteSummon(data) => Some(data.timer),
996            CharacterState::UseItem(data) => Some(data.timer),
997            CharacterState::Interact(data) => Some(data.timer),
998            CharacterState::FinisherMelee(data) => Some(data.timer),
999            CharacterState::Music(data) => Some(data.timer),
1000            CharacterState::DiveMelee(data) => Some(data.timer),
1001            CharacterState::RiposteMelee(data) => Some(data.timer),
1002            CharacterState::RapidMelee(data) => Some(data.timer),
1003            CharacterState::Transform(data) => Some(data.timer),
1004            CharacterState::RegrowHead(data) => Some(data.timer),
1005            CharacterState::StaticAura(data) => Some(data.timer),
1006        }
1007    }
1008
1009    pub fn attack_kind(&self) -> Option<AttackSource> {
1010        match self {
1011            CharacterState::Idle(_) => None,
1012            CharacterState::Crawl => None,
1013            CharacterState::Talk(_) => None,
1014            CharacterState::Climb(_) => None,
1015            CharacterState::Wallrun(_) => None,
1016            CharacterState::Skate(_) => None,
1017            CharacterState::Glide(_) => None,
1018            CharacterState::GlideWield(_) => None,
1019            CharacterState::Stunned(_) => None,
1020            CharacterState::Sit => None,
1021            CharacterState::Dance => None,
1022            CharacterState::BasicBlock(_) => None,
1023            CharacterState::Roll(_) => None,
1024            CharacterState::Wielding(_) => None,
1025            CharacterState::Equipping(_) => None,
1026            CharacterState::ComboMelee2(_) => Some(AttackSource::Melee),
1027            CharacterState::BasicMelee(_) => Some(AttackSource::Melee),
1028            CharacterState::BasicRanged(data) => {
1029                Some(if data.static_data.projectile.is_explosive() {
1030                    AttackSource::Explosion
1031                } else {
1032                    AttackSource::Projectile
1033                })
1034            },
1035            CharacterState::Boost(_) => None,
1036            CharacterState::DashMelee(_) => Some(AttackSource::Melee),
1037            CharacterState::LeapMelee(_) => Some(AttackSource::Melee),
1038            CharacterState::ChargedMelee(_) => Some(AttackSource::Melee),
1039            // TODO: When charged ranged not only arrow make this check projectile type
1040            CharacterState::ChargedRanged(_) => Some(AttackSource::Projectile),
1041            CharacterState::RepeaterRanged(data) => {
1042                Some(if data.static_data.projectile.is_explosive() {
1043                    AttackSource::Explosion
1044                } else {
1045                    AttackSource::Projectile
1046                })
1047            },
1048            CharacterState::Shockwave(data) => {
1049                Some(data.static_data.dodgeable.shockwave_attack_source())
1050            },
1051            CharacterState::LeapShockwave(data) => {
1052                Some(data.static_data.dodgeable.shockwave_attack_source())
1053            },
1054            CharacterState::BasicBeam(_) => Some(AttackSource::Beam),
1055            CharacterState::BasicAura(_) => None,
1056            CharacterState::Blink(_) => None,
1057            CharacterState::BasicSummon(_) => None,
1058            CharacterState::SelfBuff(_) => None,
1059            CharacterState::SpriteSummon(_) => None,
1060            CharacterState::UseItem(_) => None,
1061            CharacterState::Interact(_) => None,
1062            CharacterState::FinisherMelee(_) => Some(AttackSource::Melee),
1063            CharacterState::Music(_) => None,
1064            CharacterState::DiveMelee(_) => Some(AttackSource::Melee),
1065            CharacterState::RiposteMelee(_) => Some(AttackSource::Melee),
1066            CharacterState::RapidMelee(_) => Some(AttackSource::Melee),
1067            CharacterState::Transform(_) => None,
1068            CharacterState::RegrowHead(_) => None,
1069            CharacterState::StaticAura(_) => None,
1070        }
1071    }
1072}
1073
1074#[derive(Default, Copy, Clone)]
1075pub struct DurationsInfo {
1076    pub buildup: Option<Duration>,
1077    pub action: Option<Duration>,
1078    pub recover: Option<Duration>,
1079    pub movement: Option<Duration>,
1080    pub charge: Option<Duration>,
1081}
1082
1083#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq)]
1084pub struct AttackFilters {
1085    pub melee: bool,
1086    pub projectiles: bool,
1087    pub beams: bool,
1088    pub ground_shockwaves: bool,
1089    pub air_shockwaves: bool,
1090    pub explosions: bool,
1091}
1092
1093impl AttackFilters {
1094    pub fn applies(&self, attack: AttackSource) -> bool {
1095        match attack {
1096            AttackSource::Melee => self.melee,
1097            AttackSource::Projectile => self.projectiles,
1098            AttackSource::Beam => self.beams,
1099            AttackSource::GroundShockwave => self.ground_shockwaves,
1100            AttackSource::AirShockwave => self.air_shockwaves,
1101            AttackSource::UndodgeableShockwave => false,
1102            AttackSource::Explosion => self.explosions,
1103        }
1104    }
1105}
1106
1107impl Default for CharacterState {
1108    fn default() -> Self {
1109        Self::Idle(idle::Data {
1110            is_sneaking: false,
1111            footwear: None,
1112            time_entered: Time(0.0),
1113        })
1114    }
1115}
1116
1117impl Component for CharacterState {
1118    type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
1119}
1120
1121/// Contains information about the visual activity of a character.
1122///
1123/// For now this only includes the direction they're looking in, but later it
1124/// might include markers indicating that they're available for
1125/// trade/interaction, more details about their stance or appearance, facial
1126/// expression, etc.
1127#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
1128pub struct CharacterActivity {
1129    /// `None` means that the look direction should be derived from the
1130    /// orientation
1131    pub look_dir: Option<Dir>,
1132    /// If the character is using a Helm, this is the y direction the
1133    /// character steering. If the character is not steering this is
1134    /// a stale value.
1135    pub steer_dir: f32,
1136    /// If true, the owner has set this pet to stay at a fixed location and
1137    /// to not engage in combat
1138    pub is_pet_staying: bool,
1139}
1140
1141impl Component for CharacterActivity {
1142    type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
1143}