mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
1031 lines
46 KiB
Rust
1031 lines
46 KiB
Rust
use crate::{
|
|
combat::AttackSource,
|
|
comp::{
|
|
ability::Capability, inventory::item::armor::Friction, item::ConsumableKind, ControlAction,
|
|
Density, Energy, InputAttr, InputKind, Ori, Pos, Vel,
|
|
},
|
|
event::{self, EmitExt, LocalEvent},
|
|
event_emitters,
|
|
resources::Time,
|
|
states::{
|
|
self,
|
|
behavior::{CharacterBehavior, JoinData},
|
|
utils::{AbilityInfo, StageSection},
|
|
*,
|
|
},
|
|
util::Dir,
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
use specs::{Component, DerefFlaggedStorage};
|
|
use std::{collections::BTreeMap, time::Duration};
|
|
use strum::Display;
|
|
|
|
/// Data returned from character behavior fn's to Character Behavior System.
|
|
pub struct StateUpdate {
|
|
pub character: CharacterState,
|
|
pub pos: Pos,
|
|
pub vel: Vel,
|
|
pub ori: Ori,
|
|
pub density: Density,
|
|
pub energy: Energy,
|
|
pub swap_equipped_weapons: bool,
|
|
pub should_strafe: bool,
|
|
pub queued_inputs: BTreeMap<InputKind, InputAttr>,
|
|
pub removed_inputs: Vec<InputKind>,
|
|
pub character_activity: CharacterActivity,
|
|
}
|
|
|
|
event_emitters! {
|
|
pub struct CharacterStateEvents[CharacterStateEventEmitters] {
|
|
combo: event::ComboChangeEvent,
|
|
event: event::AuraEvent,
|
|
shoot: event::ShootEvent,
|
|
teleport_to: event::TeleportToEvent,
|
|
shockwave: event::ShockwaveEvent,
|
|
explosion: event::ExplosionEvent,
|
|
buff: event::BuffEvent,
|
|
inventory_manip: event::InventoryManipEvent,
|
|
sprite_summon: event::CreateSpriteEvent,
|
|
change_stance: event::ChangeStanceEvent,
|
|
create_npc: event::CreateNpcEvent,
|
|
energy_change: event::EnergyChangeEvent,
|
|
knockback: event::KnockbackEvent,
|
|
sprite_light: event::ToggleSpriteLightEvent,
|
|
}
|
|
}
|
|
|
|
pub struct OutputEvents<'a, 'b> {
|
|
local: &'a mut Vec<LocalEvent>,
|
|
server: &'a mut CharacterStateEventEmitters<'b>,
|
|
}
|
|
|
|
impl<'a, 'b: 'a> OutputEvents<'a, 'b> {
|
|
pub fn new(
|
|
local: &'a mut Vec<LocalEvent>,
|
|
server: &'a mut CharacterStateEventEmitters<'b>,
|
|
) -> Self {
|
|
Self { local, server }
|
|
}
|
|
|
|
pub fn emit_local(&mut self, event: LocalEvent) { self.local.push(event); }
|
|
|
|
pub fn emit_server<E>(&mut self, event: E)
|
|
where
|
|
CharacterStateEventEmitters<'b>: EmitExt<E>,
|
|
{
|
|
self.server.emit(event);
|
|
}
|
|
}
|
|
|
|
impl From<&JoinData<'_>> for StateUpdate {
|
|
fn from(data: &JoinData) -> Self {
|
|
StateUpdate {
|
|
pos: *data.pos,
|
|
vel: *data.vel,
|
|
ori: *data.ori,
|
|
density: *data.density,
|
|
energy: *data.energy,
|
|
swap_equipped_weapons: false,
|
|
should_strafe: data.inputs.strafing,
|
|
character: data.character.clone(),
|
|
queued_inputs: BTreeMap::new(),
|
|
removed_inputs: Vec::new(),
|
|
character_activity: *data.character_activity,
|
|
}
|
|
}
|
|
}
|
|
#[derive(Clone, Debug, Display, PartialEq, Serialize, Deserialize)]
|
|
pub enum CharacterState {
|
|
Idle(idle::Data),
|
|
Climb(climb::Data),
|
|
Sit,
|
|
Dance,
|
|
Talk,
|
|
Glide(glide::Data),
|
|
GlideWield(glide_wield::Data),
|
|
/// A stunned state
|
|
Stunned(stunned::Data),
|
|
/// A basic blocking state
|
|
BasicBlock(basic_block::Data),
|
|
/// Player is busy equipping or unequipping weapons
|
|
Equipping(equipping::Data),
|
|
/// Player is holding a weapon and can perform other actions
|
|
Wielding(wielding::Data),
|
|
/// A dodge where player can roll
|
|
Roll(roll::Data),
|
|
/// A basic melee attack (e.g. sword)
|
|
BasicMelee(basic_melee::Data),
|
|
/// A basic ranged attack (e.g. bow)
|
|
BasicRanged(basic_ranged::Data),
|
|
/// A force will boost you into a direction for some duration
|
|
Boost(boost::Data),
|
|
/// Dash forward and then attack
|
|
DashMelee(dash_melee::Data),
|
|
/// A three-stage attack where each attack pushes player forward
|
|
/// and successive attacks increase in damage, while player holds button.
|
|
ComboMeleeDeprecated(combo_melee::Data),
|
|
/// A state where you progress through multiple melee attacks
|
|
ComboMelee2(combo_melee2::Data),
|
|
/// A leap followed by a small aoe ground attack
|
|
LeapMelee(leap_melee::Data),
|
|
/// A leap followed by a shockwave
|
|
LeapShockwave(leap_shockwave::Data),
|
|
/// A charged ranged attack (e.g. bow)
|
|
ChargedRanged(charged_ranged::Data),
|
|
/// A charged melee attack
|
|
ChargedMelee(charged_melee::Data),
|
|
/// A repeating ranged attack
|
|
RepeaterRanged(repeater_ranged::Data),
|
|
/// A ground shockwave attack
|
|
Shockwave(shockwave::Data),
|
|
/// A continuous attack that affects all creatures in a cone originating
|
|
/// from the source
|
|
BasicBeam(basic_beam::Data),
|
|
/// Creates an aura that persists as long as you are actively casting
|
|
BasicAura(basic_aura::Data),
|
|
/// A short teleport that targets either a position or entity
|
|
Blink(blink::Data),
|
|
/// Summons creatures that fight for the caster
|
|
BasicSummon(basic_summon::Data),
|
|
/// Inserts a buff on the caster
|
|
SelfBuff(self_buff::Data),
|
|
/// Creates sprites around the caster
|
|
SpriteSummon(sprite_summon::Data),
|
|
/// Handles logic for using an item so it is not simply instant
|
|
UseItem(use_item::Data),
|
|
/// Handles logic for interacting with a sprite, e.g. using a chest or
|
|
/// picking a plant
|
|
SpriteInteract(sprite_interact::Data),
|
|
/// Runs on the wall
|
|
Wallrun(wallrun::Data),
|
|
/// Ice skating or skiing
|
|
Skate(skate::Data),
|
|
/// Play music instrument
|
|
Music(music::Data),
|
|
/// Melee attack that scales off and consumes combo
|
|
FinisherMelee(finisher_melee::Data),
|
|
/// State entered when diving, melee attack triggered upon landing on the
|
|
/// ground
|
|
DiveMelee(dive_melee::Data),
|
|
/// Attack that attempts to parry, and if it parries moves to an attack
|
|
RiposteMelee(riposte_melee::Data),
|
|
/// A series of consecutive, identical attacks that only go through buildup
|
|
/// and recover once for the entire state
|
|
RapidMelee(rapid_melee::Data),
|
|
}
|
|
|
|
impl CharacterState {
|
|
pub fn is_wield(&self) -> bool {
|
|
matches!(
|
|
self,
|
|
CharacterState::Wielding(_)
|
|
| CharacterState::BasicMelee(_)
|
|
| CharacterState::BasicRanged(_)
|
|
| CharacterState::DashMelee(_)
|
|
| CharacterState::ComboMeleeDeprecated(_)
|
|
| CharacterState::ComboMelee2(_)
|
|
| CharacterState::BasicBlock(_)
|
|
| CharacterState::LeapMelee(_)
|
|
| CharacterState::LeapShockwave(_)
|
|
| CharacterState::ChargedMelee(_)
|
|
| CharacterState::ChargedRanged(_)
|
|
| CharacterState::RepeaterRanged(_)
|
|
| CharacterState::Shockwave(_)
|
|
| CharacterState::BasicBeam(_)
|
|
| CharacterState::BasicAura(_)
|
|
| CharacterState::SelfBuff(_)
|
|
| CharacterState::Blink(_)
|
|
| CharacterState::Music(_)
|
|
| CharacterState::BasicSummon(_)
|
|
| CharacterState::SpriteSummon(_)
|
|
| CharacterState::Roll(roll::Data {
|
|
was_wielded: true,
|
|
..
|
|
})
|
|
| CharacterState::Wallrun(wallrun::Data { was_wielded: true })
|
|
| CharacterState::Stunned(stunned::Data {
|
|
was_wielded: true,
|
|
..
|
|
})
|
|
| CharacterState::FinisherMelee(_)
|
|
| CharacterState::DiveMelee(_)
|
|
| CharacterState::RiposteMelee(_)
|
|
| CharacterState::RapidMelee(_)
|
|
)
|
|
}
|
|
|
|
pub fn was_wielded(&self) -> bool {
|
|
match self {
|
|
CharacterState::Roll(data) => data.was_wielded,
|
|
CharacterState::Stunned(data) => data.was_wielded,
|
|
CharacterState::SpriteInteract(data) => data.static_data.was_wielded,
|
|
CharacterState::UseItem(data) => data.static_data.was_wielded,
|
|
CharacterState::Wallrun(data) => data.was_wielded,
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn is_stealthy(&self) -> bool {
|
|
matches!(
|
|
self,
|
|
CharacterState::Idle(idle::Data {
|
|
is_sneaking: true,
|
|
footwear: _,
|
|
time_entered: _,
|
|
}) | CharacterState::Wielding(wielding::Data {
|
|
is_sneaking: true,
|
|
..
|
|
}) | CharacterState::Roll(roll::Data {
|
|
is_sneaking: true,
|
|
..
|
|
})
|
|
)
|
|
}
|
|
|
|
pub fn is_attack(&self) -> bool {
|
|
matches!(
|
|
self,
|
|
CharacterState::BasicMelee(_)
|
|
| CharacterState::BasicRanged(_)
|
|
| CharacterState::DashMelee(_)
|
|
| CharacterState::ComboMeleeDeprecated(_)
|
|
| CharacterState::ComboMelee2(_)
|
|
| CharacterState::LeapMelee(_)
|
|
| CharacterState::LeapShockwave(_)
|
|
| CharacterState::ChargedMelee(_)
|
|
| CharacterState::ChargedRanged(_)
|
|
| CharacterState::RepeaterRanged(_)
|
|
| CharacterState::Shockwave(_)
|
|
| CharacterState::BasicBeam(_)
|
|
| CharacterState::BasicAura(_)
|
|
| CharacterState::SelfBuff(_)
|
|
| CharacterState::Blink(_)
|
|
| CharacterState::BasicSummon(_)
|
|
| CharacterState::SpriteSummon(_)
|
|
| CharacterState::FinisherMelee(_)
|
|
| CharacterState::DiveMelee(_)
|
|
| CharacterState::RiposteMelee(_)
|
|
| CharacterState::RapidMelee(_)
|
|
)
|
|
}
|
|
|
|
pub fn is_aimed(&self) -> bool {
|
|
matches!(
|
|
self,
|
|
CharacterState::BasicMelee(_)
|
|
| CharacterState::BasicRanged(_)
|
|
| CharacterState::DashMelee(_)
|
|
| CharacterState::ComboMeleeDeprecated(_)
|
|
| CharacterState::ComboMelee2(_)
|
|
| CharacterState::BasicBlock(_)
|
|
| CharacterState::LeapMelee(_)
|
|
| CharacterState::LeapShockwave(_)
|
|
| CharacterState::ChargedMelee(_)
|
|
| CharacterState::ChargedRanged(_)
|
|
| CharacterState::RepeaterRanged(_)
|
|
| CharacterState::Shockwave(_)
|
|
| CharacterState::BasicBeam(_)
|
|
| CharacterState::Stunned(_)
|
|
| CharacterState::Wielding(_)
|
|
| CharacterState::Talk
|
|
| CharacterState::FinisherMelee(_)
|
|
| CharacterState::DiveMelee(_)
|
|
| CharacterState::RiposteMelee(_)
|
|
| CharacterState::RapidMelee(_)
|
|
)
|
|
}
|
|
|
|
pub fn is_using_hands(&self) -> bool {
|
|
matches!(
|
|
self,
|
|
CharacterState::Climb(_)
|
|
| CharacterState::Equipping(_)
|
|
| CharacterState::Dance
|
|
| CharacterState::Glide(_)
|
|
| CharacterState::GlideWield(_)
|
|
| CharacterState::Talk
|
|
| CharacterState::Roll(_),
|
|
)
|
|
}
|
|
|
|
pub fn block_strength(&self, attack_source: AttackSource) -> Option<f32> {
|
|
let from_capability = if let AttackSource::Melee = attack_source {
|
|
if let Some(capabilities) = self
|
|
.ability_info()
|
|
.map(|a| a.ability_meta)
|
|
.map(|m| m.capabilities)
|
|
{
|
|
(capabilities.contains(Capability::BLOCKS)
|
|
&& matches!(
|
|
self.stage_section(),
|
|
Some(StageSection::Buildup | StageSection::Action)
|
|
))
|
|
.then_some(0.5)
|
|
} else {
|
|
None
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
let from_state = match self {
|
|
CharacterState::BasicBlock(c) => c
|
|
.static_data
|
|
.blocked_attacks
|
|
.applies(attack_source)
|
|
.then_some(c.static_data.block_strength),
|
|
_ => None,
|
|
};
|
|
match (from_capability, from_state) {
|
|
(Some(a), Some(b)) => Some(a.max(b)),
|
|
(Some(a), None) | (None, Some(a)) => Some(a),
|
|
(None, None) => None,
|
|
}
|
|
}
|
|
|
|
pub fn is_parry(&self, attack_source: AttackSource) -> bool {
|
|
let melee = matches!(attack_source, AttackSource::Melee);
|
|
let from_capability = melee
|
|
&& self
|
|
.ability_info()
|
|
.map(|a| a.ability_meta.capabilities)
|
|
.map_or(false, |c| {
|
|
c.contains(Capability::PARRIES)
|
|
&& matches!(
|
|
self.stage_section(),
|
|
Some(StageSection::Buildup | StageSection::Action)
|
|
)
|
|
});
|
|
let from_state = match self {
|
|
CharacterState::BasicBlock(c) => c.is_parry(attack_source),
|
|
CharacterState::RiposteMelee(c) => {
|
|
melee
|
|
&& matches!(
|
|
c.stage_section,
|
|
StageSection::Buildup | StageSection::Action
|
|
)
|
|
},
|
|
_ => false,
|
|
};
|
|
from_capability || from_state
|
|
}
|
|
|
|
/// In radians
|
|
pub fn block_angle(&self) -> f32 {
|
|
match self {
|
|
CharacterState::BasicBlock(c) => c.static_data.max_angle.to_radians(),
|
|
CharacterState::ComboMelee2(c) => {
|
|
let strike_data =
|
|
c.static_data.strikes[c.completed_strikes % c.static_data.strikes.len()];
|
|
strike_data.melee_constructor.angle.to_radians()
|
|
},
|
|
CharacterState::RiposteMelee(c) => c.static_data.melee_constructor.angle.to_radians(),
|
|
// TODO: Add more here as needed, maybe look into having character state return the
|
|
// melee constructor if it has one and using that?
|
|
_ => 0.0,
|
|
}
|
|
}
|
|
|
|
pub fn is_dodge(&self) -> bool { matches!(self, CharacterState::Roll(_)) }
|
|
|
|
pub fn is_glide(&self) -> bool { matches!(self, CharacterState::Glide(_)) }
|
|
|
|
pub fn is_skate(&self) -> bool { matches!(self, CharacterState::Skate(_)) }
|
|
|
|
pub fn is_music(&self) -> bool { matches!(self, CharacterState::Music(_)) }
|
|
|
|
pub fn attack_immunities(&self) -> Option<AttackFilters> {
|
|
if let CharacterState::Roll(c) = self {
|
|
Some(c.static_data.attack_immunities)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn is_stunned(&self) -> bool { matches!(self, CharacterState::Stunned(_)) }
|
|
|
|
pub fn is_forced_movement(&self) -> bool {
|
|
matches!(self,
|
|
CharacterState::ComboMeleeDeprecated(s) if s.stage_section == StageSection::Action)
|
|
|| matches!(self, CharacterState::ComboMelee2(s) if s.stage_section == StageSection::Action)
|
|
|| matches!(self, CharacterState::DashMelee(s) if s.stage_section == StageSection::Charge)
|
|
|| matches!(self, CharacterState::LeapMelee(s) if s.stage_section == StageSection::Movement)
|
|
|| matches!(self, CharacterState::Roll(s) if s.stage_section == StageSection::Movement)
|
|
}
|
|
|
|
pub fn is_melee_attack(&self) -> bool {
|
|
matches!(self.attack_kind(), Some(AttackSource::Melee))
|
|
}
|
|
|
|
pub fn is_beam_attack(&self) -> bool { matches!(self.attack_kind(), Some(AttackSource::Beam)) }
|
|
|
|
pub fn can_perform_mounted(&self) -> bool {
|
|
matches!(
|
|
self,
|
|
CharacterState::Idle(_)
|
|
| CharacterState::Sit
|
|
| CharacterState::Dance
|
|
| CharacterState::Talk
|
|
| CharacterState::Stunned(_)
|
|
| CharacterState::BasicBlock(_)
|
|
| CharacterState::Equipping(_)
|
|
| CharacterState::Wielding(_)
|
|
| CharacterState::BasicMelee(_)
|
|
| CharacterState::BasicRanged(_)
|
|
| CharacterState::ComboMeleeDeprecated(_)
|
|
| CharacterState::ComboMelee2(_)
|
|
| CharacterState::ChargedRanged(_)
|
|
| CharacterState::RepeaterRanged(_)
|
|
| CharacterState::BasicBeam(_)
|
|
| CharacterState::BasicAura(_)
|
|
| CharacterState::BasicSummon(_)
|
|
| CharacterState::SelfBuff(_)
|
|
| CharacterState::SpriteSummon(_)
|
|
| CharacterState::UseItem(_)
|
|
| CharacterState::SpriteInteract(_)
|
|
| CharacterState::Music(_)
|
|
| CharacterState::RiposteMelee(_)
|
|
| CharacterState::RapidMelee(_)
|
|
)
|
|
}
|
|
|
|
pub fn is_sitting(&self) -> bool {
|
|
use use_item::{Data, ItemUseKind, StaticData};
|
|
matches!(
|
|
self,
|
|
CharacterState::Sit
|
|
| CharacterState::UseItem(Data {
|
|
static_data: StaticData {
|
|
item_kind: ItemUseKind::Consumable(
|
|
ConsumableKind::ComplexFood | ConsumableKind::Food
|
|
),
|
|
..
|
|
},
|
|
..
|
|
})
|
|
)
|
|
}
|
|
|
|
/// Compares for shallow equality (does not check internal struct equality)
|
|
pub fn same_variant(&self, other: &Self) -> bool {
|
|
// Check if state is the same without looking at the inner data
|
|
std::mem::discriminant(self) == std::mem::discriminant(other)
|
|
}
|
|
|
|
pub fn behavior(&self, j: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
|
|
match &self {
|
|
CharacterState::Idle(data) => data.behavior(j, output_events),
|
|
CharacterState::Talk => talk::Data.behavior(j, output_events),
|
|
CharacterState::Climb(data) => data.behavior(j, output_events),
|
|
CharacterState::Wallrun(data) => data.behavior(j, output_events),
|
|
CharacterState::Glide(data) => data.behavior(j, output_events),
|
|
CharacterState::GlideWield(data) => data.behavior(j, output_events),
|
|
CharacterState::Stunned(data) => data.behavior(j, output_events),
|
|
CharacterState::Sit => sit::Data::behavior(&sit::Data, j, output_events),
|
|
CharacterState::Dance => dance::Data::behavior(&dance::Data, j, output_events),
|
|
CharacterState::BasicBlock(data) => data.behavior(j, output_events),
|
|
CharacterState::Roll(data) => data.behavior(j, output_events),
|
|
CharacterState::Wielding(data) => data.behavior(j, output_events),
|
|
CharacterState::Equipping(data) => data.behavior(j, output_events),
|
|
CharacterState::ComboMeleeDeprecated(data) => data.behavior(j, output_events),
|
|
CharacterState::ComboMelee2(data) => data.behavior(j, output_events),
|
|
CharacterState::BasicMelee(data) => data.behavior(j, output_events),
|
|
CharacterState::BasicRanged(data) => data.behavior(j, output_events),
|
|
CharacterState::Boost(data) => data.behavior(j, output_events),
|
|
CharacterState::DashMelee(data) => data.behavior(j, output_events),
|
|
CharacterState::LeapMelee(data) => data.behavior(j, output_events),
|
|
CharacterState::LeapShockwave(data) => data.behavior(j, output_events),
|
|
CharacterState::ChargedMelee(data) => data.behavior(j, output_events),
|
|
CharacterState::ChargedRanged(data) => data.behavior(j, output_events),
|
|
CharacterState::RepeaterRanged(data) => data.behavior(j, output_events),
|
|
CharacterState::Shockwave(data) => data.behavior(j, output_events),
|
|
CharacterState::BasicBeam(data) => data.behavior(j, output_events),
|
|
CharacterState::BasicAura(data) => data.behavior(j, output_events),
|
|
CharacterState::Blink(data) => data.behavior(j, output_events),
|
|
CharacterState::BasicSummon(data) => data.behavior(j, output_events),
|
|
CharacterState::SelfBuff(data) => data.behavior(j, output_events),
|
|
CharacterState::SpriteSummon(data) => data.behavior(j, output_events),
|
|
CharacterState::UseItem(data) => data.behavior(j, output_events),
|
|
CharacterState::SpriteInteract(data) => data.behavior(j, output_events),
|
|
CharacterState::Skate(data) => data.behavior(j, output_events),
|
|
CharacterState::Music(data) => data.behavior(j, output_events),
|
|
CharacterState::FinisherMelee(data) => data.behavior(j, output_events),
|
|
CharacterState::DiveMelee(data) => data.behavior(j, output_events),
|
|
CharacterState::RiposteMelee(data) => data.behavior(j, output_events),
|
|
CharacterState::RapidMelee(data) => data.behavior(j, output_events),
|
|
}
|
|
}
|
|
|
|
pub fn handle_event(
|
|
&self,
|
|
j: &JoinData,
|
|
output_events: &mut OutputEvents,
|
|
action: ControlAction,
|
|
) -> StateUpdate {
|
|
match &self {
|
|
CharacterState::Idle(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Talk => talk::Data.handle_event(j, output_events, action),
|
|
CharacterState::Climb(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Wallrun(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Glide(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::GlideWield(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Stunned(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Sit => {
|
|
states::sit::Data::handle_event(&sit::Data, j, output_events, action)
|
|
},
|
|
CharacterState::Dance => {
|
|
states::dance::Data::handle_event(&dance::Data, j, output_events, action)
|
|
},
|
|
CharacterState::BasicBlock(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Roll(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Wielding(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Equipping(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::ComboMeleeDeprecated(data) => {
|
|
data.handle_event(j, output_events, action)
|
|
},
|
|
CharacterState::ComboMelee2(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::BasicMelee(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::BasicRanged(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Boost(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::DashMelee(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::LeapMelee(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::LeapShockwave(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::ChargedMelee(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::ChargedRanged(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::RepeaterRanged(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Shockwave(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::BasicBeam(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::BasicAura(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Blink(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::BasicSummon(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::SelfBuff(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::SpriteSummon(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::UseItem(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::SpriteInteract(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Skate(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::Music(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::FinisherMelee(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::DiveMelee(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::RiposteMelee(data) => data.handle_event(j, output_events, action),
|
|
CharacterState::RapidMelee(data) => data.handle_event(j, output_events, action),
|
|
}
|
|
}
|
|
|
|
pub fn footwear(&self) -> Option<Friction> {
|
|
match &self {
|
|
CharacterState::Idle(data) => data.footwear,
|
|
CharacterState::Skate(data) => Some(data.footwear),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn ability_info(&self) -> Option<AbilityInfo> {
|
|
match &self {
|
|
CharacterState::Idle(_) => None,
|
|
CharacterState::Talk => None,
|
|
CharacterState::Climb(_) => None,
|
|
CharacterState::Wallrun(_) => None,
|
|
CharacterState::Skate(_) => None,
|
|
CharacterState::Glide(_) => None,
|
|
CharacterState::GlideWield(_) => None,
|
|
CharacterState::Stunned(_) => None,
|
|
CharacterState::Sit => None,
|
|
CharacterState::Dance => None,
|
|
CharacterState::BasicBlock(data) => Some(data.static_data.ability_info),
|
|
CharacterState::Roll(data) => Some(data.static_data.ability_info),
|
|
CharacterState::Wielding(_) => None,
|
|
CharacterState::Equipping(_) => None,
|
|
CharacterState::ComboMeleeDeprecated(data) => Some(data.static_data.ability_info),
|
|
CharacterState::ComboMelee2(data) => Some(data.static_data.ability_info),
|
|
CharacterState::BasicMelee(data) => Some(data.static_data.ability_info),
|
|
CharacterState::BasicRanged(data) => Some(data.static_data.ability_info),
|
|
CharacterState::Boost(data) => Some(data.static_data.ability_info),
|
|
CharacterState::DashMelee(data) => Some(data.static_data.ability_info),
|
|
CharacterState::LeapMelee(data) => Some(data.static_data.ability_info),
|
|
CharacterState::LeapShockwave(data) => Some(data.static_data.ability_info),
|
|
CharacterState::ChargedMelee(data) => Some(data.static_data.ability_info),
|
|
CharacterState::ChargedRanged(data) => Some(data.static_data.ability_info),
|
|
CharacterState::RepeaterRanged(data) => Some(data.static_data.ability_info),
|
|
CharacterState::Shockwave(data) => Some(data.static_data.ability_info),
|
|
CharacterState::BasicBeam(data) => Some(data.static_data.ability_info),
|
|
CharacterState::BasicAura(data) => Some(data.static_data.ability_info),
|
|
CharacterState::Blink(data) => Some(data.static_data.ability_info),
|
|
CharacterState::BasicSummon(data) => Some(data.static_data.ability_info),
|
|
CharacterState::SelfBuff(data) => Some(data.static_data.ability_info),
|
|
CharacterState::SpriteSummon(data) => Some(data.static_data.ability_info),
|
|
CharacterState::UseItem(_) => None,
|
|
CharacterState::SpriteInteract(_) => None,
|
|
CharacterState::FinisherMelee(data) => Some(data.static_data.ability_info),
|
|
CharacterState::Music(data) => Some(data.static_data.ability_info),
|
|
CharacterState::DiveMelee(data) => Some(data.static_data.ability_info),
|
|
CharacterState::RiposteMelee(data) => Some(data.static_data.ability_info),
|
|
CharacterState::RapidMelee(data) => Some(data.static_data.ability_info),
|
|
}
|
|
}
|
|
|
|
pub fn stage_section(&self) -> Option<StageSection> {
|
|
match &self {
|
|
CharacterState::Idle(_) => None,
|
|
CharacterState::Talk => None,
|
|
CharacterState::Climb(_) => None,
|
|
CharacterState::Wallrun(_) => None,
|
|
CharacterState::Skate(_) => None,
|
|
CharacterState::Glide(_) => None,
|
|
CharacterState::GlideWield(_) => None,
|
|
CharacterState::Stunned(data) => Some(data.stage_section),
|
|
CharacterState::Sit => None,
|
|
CharacterState::Dance => None,
|
|
CharacterState::BasicBlock(data) => Some(data.stage_section),
|
|
CharacterState::Roll(data) => Some(data.stage_section),
|
|
CharacterState::Equipping(_) => Some(StageSection::Buildup),
|
|
CharacterState::Wielding(_) => None,
|
|
CharacterState::ComboMeleeDeprecated(data) => Some(data.stage_section),
|
|
CharacterState::ComboMelee2(data) => Some(data.stage_section),
|
|
CharacterState::BasicMelee(data) => Some(data.stage_section),
|
|
CharacterState::BasicRanged(data) => Some(data.stage_section),
|
|
CharacterState::Boost(_) => None,
|
|
CharacterState::DashMelee(data) => Some(data.stage_section),
|
|
CharacterState::LeapMelee(data) => Some(data.stage_section),
|
|
CharacterState::LeapShockwave(data) => Some(data.stage_section),
|
|
CharacterState::ChargedMelee(data) => Some(data.stage_section),
|
|
CharacterState::ChargedRanged(data) => Some(data.stage_section),
|
|
CharacterState::RepeaterRanged(data) => Some(data.stage_section),
|
|
CharacterState::Shockwave(data) => Some(data.stage_section),
|
|
CharacterState::BasicBeam(data) => Some(data.stage_section),
|
|
CharacterState::BasicAura(data) => Some(data.stage_section),
|
|
CharacterState::Blink(data) => Some(data.stage_section),
|
|
CharacterState::BasicSummon(data) => Some(data.stage_section),
|
|
CharacterState::SelfBuff(data) => Some(data.stage_section),
|
|
CharacterState::SpriteSummon(data) => Some(data.stage_section),
|
|
CharacterState::UseItem(data) => Some(data.stage_section),
|
|
CharacterState::SpriteInteract(data) => Some(data.stage_section),
|
|
CharacterState::FinisherMelee(data) => Some(data.stage_section),
|
|
CharacterState::Music(data) => Some(data.stage_section),
|
|
CharacterState::DiveMelee(data) => Some(data.stage_section),
|
|
CharacterState::RiposteMelee(data) => Some(data.stage_section),
|
|
CharacterState::RapidMelee(data) => Some(data.stage_section),
|
|
}
|
|
}
|
|
|
|
pub fn durations(&self) -> Option<DurationsInfo> {
|
|
match &self {
|
|
CharacterState::Idle(_) => None,
|
|
CharacterState::Talk => None,
|
|
CharacterState::Climb(_) => None,
|
|
CharacterState::Wallrun(_) => None,
|
|
CharacterState::Skate(_) => None,
|
|
CharacterState::Glide(_) => None,
|
|
CharacterState::GlideWield(_) => None,
|
|
CharacterState::Stunned(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::Sit => None,
|
|
CharacterState::Dance => None,
|
|
CharacterState::BasicBlock(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::Roll(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
movement: Some(data.static_data.movement_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::Wielding(_) => None,
|
|
CharacterState::Equipping(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::ComboMeleeDeprecated(data) => {
|
|
let stage_index = data.stage_index();
|
|
let stage = data.static_data.stage_data[stage_index];
|
|
Some(DurationsInfo {
|
|
buildup: Some(stage.base_buildup_duration),
|
|
action: Some(stage.base_swing_duration),
|
|
recover: Some(stage.base_recover_duration),
|
|
..Default::default()
|
|
})
|
|
},
|
|
CharacterState::ComboMelee2(data) => {
|
|
let strike = data.strike_data();
|
|
Some(DurationsInfo {
|
|
buildup: Some(strike.buildup_duration),
|
|
action: Some(strike.swing_duration),
|
|
recover: Some(strike.recover_duration),
|
|
..Default::default()
|
|
})
|
|
},
|
|
CharacterState::BasicMelee(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.swing_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::BasicRanged(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::Boost(data) => Some(DurationsInfo {
|
|
movement: Some(data.static_data.movement_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::DashMelee(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.swing_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
charge: Some(data.static_data.charge_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::LeapMelee(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.swing_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
movement: Some(data.static_data.movement_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::LeapShockwave(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.swing_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
movement: Some(data.static_data.movement_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::ChargedMelee(data) => Some(DurationsInfo {
|
|
action: Some(data.static_data.swing_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
charge: Some(data.static_data.charge_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::ChargedRanged(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
charge: Some(data.static_data.charge_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::RepeaterRanged(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.shoot_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::Shockwave(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.swing_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::BasicBeam(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::BasicAura(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.cast_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::Blink(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::BasicSummon(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.cast_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::SelfBuff(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.cast_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::SpriteSummon(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.cast_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::UseItem(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.use_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::SpriteInteract(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.use_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::FinisherMelee(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.swing_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::Music(data) => Some(DurationsInfo {
|
|
action: Some(data.static_data.play_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::DiveMelee(data) => Some(DurationsInfo {
|
|
action: Some(data.static_data.swing_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
movement: Some(data.static_data.movement_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::RiposteMelee(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.swing_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
CharacterState::RapidMelee(data) => Some(DurationsInfo {
|
|
buildup: Some(data.static_data.buildup_duration),
|
|
action: Some(data.static_data.swing_duration),
|
|
recover: Some(data.static_data.recover_duration),
|
|
..Default::default()
|
|
}),
|
|
}
|
|
}
|
|
|
|
pub fn timer(&self) -> Option<Duration> {
|
|
match &self {
|
|
CharacterState::Idle(_) => None,
|
|
CharacterState::Talk => None,
|
|
CharacterState::Climb(_) => None,
|
|
CharacterState::Wallrun(_) => None,
|
|
CharacterState::Skate(_) => None,
|
|
CharacterState::Glide(data) => Some(data.timer),
|
|
CharacterState::GlideWield(_) => None,
|
|
CharacterState::Stunned(data) => Some(data.timer),
|
|
CharacterState::Sit => None,
|
|
CharacterState::Dance => None,
|
|
CharacterState::BasicBlock(data) => Some(data.timer),
|
|
CharacterState::Roll(data) => Some(data.timer),
|
|
CharacterState::Wielding(_) => None,
|
|
CharacterState::Equipping(data) => Some(data.timer),
|
|
CharacterState::ComboMeleeDeprecated(data) => Some(data.timer),
|
|
CharacterState::ComboMelee2(data) => Some(data.timer),
|
|
CharacterState::BasicMelee(data) => Some(data.timer),
|
|
CharacterState::BasicRanged(data) => Some(data.timer),
|
|
CharacterState::Boost(data) => Some(data.timer),
|
|
CharacterState::DashMelee(data) => Some(data.timer),
|
|
CharacterState::LeapMelee(data) => Some(data.timer),
|
|
CharacterState::LeapShockwave(data) => Some(data.timer),
|
|
CharacterState::ChargedMelee(data) => Some(data.timer),
|
|
CharacterState::ChargedRanged(data) => Some(data.timer),
|
|
CharacterState::RepeaterRanged(data) => Some(data.timer),
|
|
CharacterState::Shockwave(data) => Some(data.timer),
|
|
CharacterState::BasicBeam(data) => Some(data.timer),
|
|
CharacterState::BasicAura(data) => Some(data.timer),
|
|
CharacterState::Blink(data) => Some(data.timer),
|
|
CharacterState::BasicSummon(data) => Some(data.timer),
|
|
CharacterState::SelfBuff(data) => Some(data.timer),
|
|
CharacterState::SpriteSummon(data) => Some(data.timer),
|
|
CharacterState::UseItem(data) => Some(data.timer),
|
|
CharacterState::SpriteInteract(data) => Some(data.timer),
|
|
CharacterState::FinisherMelee(data) => Some(data.timer),
|
|
CharacterState::Music(data) => Some(data.timer),
|
|
CharacterState::DiveMelee(data) => Some(data.timer),
|
|
CharacterState::RiposteMelee(data) => Some(data.timer),
|
|
CharacterState::RapidMelee(data) => Some(data.timer),
|
|
}
|
|
}
|
|
|
|
pub fn attack_kind(&self) -> Option<AttackSource> {
|
|
match self {
|
|
CharacterState::Idle(_) => None,
|
|
CharacterState::Talk => None,
|
|
CharacterState::Climb(_) => None,
|
|
CharacterState::Wallrun(_) => None,
|
|
CharacterState::Skate(_) => None,
|
|
CharacterState::Glide(_) => None,
|
|
CharacterState::GlideWield(_) => None,
|
|
CharacterState::Stunned(_) => None,
|
|
CharacterState::Sit => None,
|
|
CharacterState::Dance => None,
|
|
CharacterState::BasicBlock(_) => None,
|
|
CharacterState::Roll(_) => None,
|
|
CharacterState::Wielding(_) => None,
|
|
CharacterState::Equipping(_) => None,
|
|
CharacterState::ComboMeleeDeprecated(_) => Some(AttackSource::Melee),
|
|
CharacterState::ComboMelee2(_) => Some(AttackSource::Melee),
|
|
CharacterState::BasicMelee(_) => Some(AttackSource::Melee),
|
|
CharacterState::BasicRanged(data) => {
|
|
Some(if data.static_data.projectile.is_explosive() {
|
|
AttackSource::Explosion
|
|
} else {
|
|
AttackSource::Projectile
|
|
})
|
|
},
|
|
CharacterState::Boost(_) => None,
|
|
CharacterState::DashMelee(_) => Some(AttackSource::Melee),
|
|
CharacterState::LeapMelee(_) => Some(AttackSource::Melee),
|
|
CharacterState::ChargedMelee(_) => Some(AttackSource::Melee),
|
|
// TODO: When charged ranged not only arrow make this check projectile type
|
|
CharacterState::ChargedRanged(_) => Some(AttackSource::Projectile),
|
|
CharacterState::RepeaterRanged(data) => {
|
|
Some(if data.static_data.projectile.is_explosive() {
|
|
AttackSource::Explosion
|
|
} else {
|
|
AttackSource::Projectile
|
|
})
|
|
},
|
|
CharacterState::Shockwave(data) => Some(data.static_data.dodgeable.to_attack_source()),
|
|
CharacterState::LeapShockwave(data) => {
|
|
Some(data.static_data.dodgeable.to_attack_source())
|
|
},
|
|
CharacterState::BasicBeam(_) => Some(AttackSource::Beam),
|
|
CharacterState::BasicAura(_) => None,
|
|
CharacterState::Blink(_) => None,
|
|
CharacterState::BasicSummon(_) => None,
|
|
CharacterState::SelfBuff(_) => None,
|
|
CharacterState::SpriteSummon(_) => None,
|
|
CharacterState::UseItem(_) => None,
|
|
CharacterState::SpriteInteract(_) => None,
|
|
CharacterState::FinisherMelee(_) => Some(AttackSource::Melee),
|
|
CharacterState::Music(_) => None,
|
|
CharacterState::DiveMelee(_) => Some(AttackSource::Melee),
|
|
CharacterState::RiposteMelee(_) => Some(AttackSource::Melee),
|
|
CharacterState::RapidMelee(_) => Some(AttackSource::Melee),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Default, Copy, Clone)]
|
|
pub struct DurationsInfo {
|
|
pub buildup: Option<Duration>,
|
|
pub action: Option<Duration>,
|
|
pub recover: Option<Duration>,
|
|
pub movement: Option<Duration>,
|
|
pub charge: Option<Duration>,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq)]
|
|
pub struct AttackFilters {
|
|
pub melee: bool,
|
|
pub projectiles: bool,
|
|
pub beams: bool,
|
|
pub ground_shockwaves: bool,
|
|
pub air_shockwaves: bool,
|
|
pub explosions: bool,
|
|
}
|
|
|
|
impl AttackFilters {
|
|
pub fn applies(&self, attack: AttackSource) -> bool {
|
|
match attack {
|
|
AttackSource::Melee => self.melee,
|
|
AttackSource::Projectile => self.projectiles,
|
|
AttackSource::Beam => self.beams,
|
|
AttackSource::GroundShockwave => self.ground_shockwaves,
|
|
AttackSource::AirShockwave => self.air_shockwaves,
|
|
AttackSource::UndodgeableShockwave => false,
|
|
AttackSource::Explosion => self.explosions,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for CharacterState {
|
|
fn default() -> Self {
|
|
Self::Idle(idle::Data {
|
|
is_sneaking: false,
|
|
footwear: None,
|
|
time_entered: Time(0.0),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Component for CharacterState {
|
|
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
|
|
}
|
|
|
|
/// Contains information about the visual activity of a character.
|
|
///
|
|
/// For now this only includes the direction they're looking in, but later it
|
|
/// might include markers indicating that they're available for
|
|
/// trade/interaction, more details about their stance or appearance, facial
|
|
/// expression, etc.
|
|
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
|
pub struct CharacterActivity {
|
|
/// `None` means that the look direction should be derived from the
|
|
/// orientation
|
|
pub look_dir: Option<Dir>,
|
|
/// If the character is using a Helm, this is the y direction the
|
|
/// character steering. If the character is not steering this is
|
|
/// a stale value.
|
|
pub steer_dir: f32,
|
|
/// If true, the owner has set this pet to stay at a fixed location and
|
|
/// to not engage in combat
|
|
pub is_pet_staying: bool,
|
|
}
|
|
|
|
impl Component for CharacterActivity {
|
|
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
|
|
}
|