mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Clean up character states
This commit is contained in:
parent
0d2b26a3b8
commit
b1d1299fe6
@ -1,39 +1,34 @@
|
||||
use crate::comp;
|
||||
use specs::{Component, FlaggedStorage, HashMapStorage, VecStorage};
|
||||
use specs::{Component, DenseVecStorage, FlaggedStorage, HashMapStorage};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum AbilityActionKind {
|
||||
Primary,
|
||||
Secondary,
|
||||
Dodge,
|
||||
Block,
|
||||
// UpdatePool?
|
||||
pub enum AbilityState {
|
||||
BasicAttack,
|
||||
BasicBlock,
|
||||
Roll,
|
||||
}
|
||||
impl Default for AbilityActionKind {
|
||||
fn default() -> Self { Self::Primary }
|
||||
impl Default for AbilityState {
|
||||
fn default() -> Self { Self::BasicAttack }
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct AbilityAction(pub AbilityActionKind);
|
||||
|
||||
impl Component for AbilityAction {
|
||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||
impl Component for AbilityState {
|
||||
type Storage = DenseVecStorage<Self>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct AbilityPool {
|
||||
pub primary: Option<comp::CharacterState>,
|
||||
pub secondary: Option<comp::CharacterState>,
|
||||
pub block: Option<comp::CharacterState>,
|
||||
pub dodge: Option<comp::CharacterState>,
|
||||
pub primary: Option<AbilityState>,
|
||||
pub secondary: Option<AbilityState>,
|
||||
pub block: Option<AbilityState>,
|
||||
pub dodge: Option<AbilityState>,
|
||||
}
|
||||
|
||||
impl Default for AbilityPool {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
primary: Some(comp::CharacterState::BasicAttack(None)),
|
||||
secondary: Some(comp::CharacterState::BasicBlock(None)),
|
||||
primary: Some(AbilityState::BasicAttack),
|
||||
secondary: Some(AbilityState::BasicAttack),
|
||||
block: None,
|
||||
dodge: Some(comp::CharacterState::Roll(None)),
|
||||
dodge: Some(AbilityState::Roll),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,12 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
AbilityPool, Body, ControllerInputs, Energy, Ori, PhysicsState, Pos, Stats, ToolData, Vel,
|
||||
},
|
||||
comp::{Energy, Ori, Pos, ToolData, Vel},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
state::DeltaTime,
|
||||
states::*,
|
||||
sync::Uid,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, Entity, FlaggedStorage, HashMapStorage, LazyUpdate, VecStorage};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
pub struct EcsStateData<'a> {
|
||||
pub entity: &'a Entity,
|
||||
pub uid: &'a Uid,
|
||||
pub character: &'a CharacterState,
|
||||
pub pos: &'a Pos,
|
||||
pub vel: &'a Vel,
|
||||
pub ori: &'a Ori,
|
||||
pub dt: &'a DeltaTime,
|
||||
pub inputs: &'a ControllerInputs,
|
||||
pub stats: &'a Stats,
|
||||
pub energy: &'a Energy,
|
||||
pub body: &'a Body,
|
||||
pub physics: &'a PhysicsState,
|
||||
pub ability_pool: &'a AbilityPool,
|
||||
pub updater: &'a LazyUpdate,
|
||||
}
|
||||
use specs::{Component, FlaggedStorage, HashMapStorage, VecStorage};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
|
||||
/// Data returned from character behavior fn's to Character Behavior System.
|
||||
pub struct StateUpdate {
|
||||
pub character: CharacterState,
|
||||
pub pos: Pos,
|
||||
@ -40,45 +19,63 @@ pub struct StateUpdate {
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum CharacterState {
|
||||
Idle(Option<idle::State>),
|
||||
Climb(Option<climb::State>),
|
||||
Sit(Option<sit::State>),
|
||||
Wielding(Option<wielding::State>),
|
||||
Wielded(Option<wielded::State>),
|
||||
Glide(Option<glide::State>),
|
||||
BasicAttack(Option<basic_attack::State>),
|
||||
BasicBlock(Option<basic_block::State>),
|
||||
//Charge(Option<charge_attack::State>),
|
||||
Roll(Option<roll::State>),
|
||||
Idle {},
|
||||
Climb {},
|
||||
Sit {},
|
||||
Equipping {
|
||||
/// The weapon being equipped
|
||||
tool: ToolData,
|
||||
/// Time left before next state
|
||||
time_left: Duration,
|
||||
},
|
||||
Wielding {
|
||||
/// The weapon being wielded
|
||||
tool: ToolData,
|
||||
},
|
||||
Glide {},
|
||||
/// A basic attacking state
|
||||
BasicAttack {
|
||||
/// How long the state has until exiting
|
||||
remaining_duration: Duration,
|
||||
/// Whether the attack can deal more damage
|
||||
exhausted: bool,
|
||||
},
|
||||
/// A basic blocking state
|
||||
BasicBlock {},
|
||||
//Charge{},
|
||||
Roll {
|
||||
/// How long the state has until exiting
|
||||
remaining_duration: Duration,
|
||||
},
|
||||
}
|
||||
|
||||
impl CharacterState {
|
||||
pub fn is_wielded(&self) -> bool {
|
||||
match self {
|
||||
CharacterState::Wielded(_) => true,
|
||||
CharacterState::BasicAttack(_) => true,
|
||||
CharacterState::BasicBlock(_) => true,
|
||||
CharacterState::Wielding { .. } => true,
|
||||
CharacterState::BasicAttack { .. } => true,
|
||||
CharacterState::BasicBlock { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_attack(&self) -> bool {
|
||||
match self {
|
||||
CharacterState::BasicAttack(_) => true,
|
||||
CharacterState::BasicAttack { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_block(&self) -> bool {
|
||||
match self {
|
||||
CharacterState::BasicBlock(_) => true,
|
||||
CharacterState::BasicBlock { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_dodge(&self) -> bool {
|
||||
match self {
|
||||
CharacterState::Roll(_) => true,
|
||||
CharacterState::Roll { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -88,53 +85,10 @@ impl CharacterState {
|
||||
// Check if state is the same without looking at the inner data
|
||||
std::mem::discriminant(self) == std::mem::discriminant(other)
|
||||
}
|
||||
|
||||
/// Passes data to variant or subvariant handlers
|
||||
/// States contain `Option<StateHandler Implementor>`s, and will be
|
||||
/// `None` if state data has not been initialized. So we have to
|
||||
/// check and intialize new state data if so.
|
||||
pub fn update(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
match self {
|
||||
CharacterState::Idle(opt_state) => opt_state
|
||||
// If data hasn't been initialized, initialize a new one
|
||||
.unwrap_or_else(|| idle::State::new(ecs_data))
|
||||
// Call handler
|
||||
.handle(ecs_data),
|
||||
CharacterState::Climb(opt_state) => opt_state
|
||||
.unwrap_or_else(|| climb::State::new(ecs_data))
|
||||
.handle(ecs_data),
|
||||
CharacterState::Sit(opt_state) => opt_state
|
||||
.unwrap_or_else(|| sit::State::new(ecs_data))
|
||||
.handle(ecs_data),
|
||||
CharacterState::Wielding(opt_state) => opt_state
|
||||
.unwrap_or_else(|| wielding::State::new(ecs_data))
|
||||
.handle(ecs_data),
|
||||
CharacterState::Wielded(opt_state) => opt_state
|
||||
.unwrap_or_else(|| wielded::State::new(ecs_data))
|
||||
.handle(ecs_data),
|
||||
CharacterState::BasicAttack(opt_state) => opt_state
|
||||
.unwrap_or_else(|| basic_attack::State::new(ecs_data))
|
||||
.handle(ecs_data),
|
||||
CharacterState::BasicBlock(opt_state) => opt_state
|
||||
.unwrap_or_else(|| basic_block::State::new(ecs_data))
|
||||
.handle(ecs_data),
|
||||
/*CharacterState::Charge(opt_state) => opt_state
|
||||
.unwrap_or_else(|| charge_attack::State::new(ecs_data))
|
||||
.handle(ecs_data),*/
|
||||
CharacterState::Roll(opt_state) => opt_state
|
||||
.unwrap_or_else(|| roll::State::new(ecs_data))
|
||||
.handle(ecs_data),
|
||||
CharacterState::Glide(opt_state) => opt_state
|
||||
.unwrap_or_else(|| glide::State::new(ecs_data))
|
||||
.handle(ecs_data),
|
||||
/* All states should be explicitly handled
|
||||
* DO NOT use default match: _ => {}, */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CharacterState {
|
||||
fn default() -> Self { Self::Idle(None) }
|
||||
fn default() -> Self { Self::Idle {} }
|
||||
}
|
||||
|
||||
impl Component for CharacterState {
|
||||
|
@ -16,14 +16,14 @@ mod stats;
|
||||
mod visual;
|
||||
|
||||
// Reexports
|
||||
pub use ability::{AbilityAction, AbilityActionKind, AbilityPool};
|
||||
pub use ability::{AbilityPool, AbilityState};
|
||||
pub use admin::Admin;
|
||||
pub use agent::{Agent, Alignment};
|
||||
pub use body::{
|
||||
biped_large, bird_medium, bird_small, critter, dragon, fish_medium, fish_small, humanoid,
|
||||
object, quadruped_medium, quadruped_small, AllBodies, Body, BodyData,
|
||||
};
|
||||
pub use character_state::{Attacking, CharacterState, EcsStateData, StateUpdate};
|
||||
pub use character_state::{Attacking, CharacterState, StateUpdate};
|
||||
pub use controller::{
|
||||
ControlEvent, Controller, ControllerInputs, Input, InputState, InventoryManip, MountState,
|
||||
Mounting,
|
||||
|
@ -21,7 +21,7 @@ sum_type! {
|
||||
Mass(comp::Mass),
|
||||
Gravity(comp::Gravity),
|
||||
Sticky(comp::Sticky),
|
||||
AbilityAction(comp::AbilityAction),
|
||||
AbilityState(comp::AbilityState),
|
||||
AbilityPool(comp::AbilityPool),
|
||||
Attacking(comp::Attacking),
|
||||
CharacterState(comp::CharacterState),
|
||||
@ -45,7 +45,7 @@ sum_type! {
|
||||
Mass(PhantomData<comp::Mass>),
|
||||
Gravity(PhantomData<comp::Gravity>),
|
||||
Sticky(PhantomData<comp::Sticky>),
|
||||
AbilityAction(PhantomData<comp::AbilityAction>),
|
||||
AbilityState(PhantomData<comp::AbilityState>),
|
||||
AbilityPool(PhantomData<comp::AbilityPool>),
|
||||
Attacking(PhantomData<comp::Attacking>),
|
||||
CharacterState(PhantomData<comp::CharacterState>),
|
||||
@ -69,7 +69,7 @@ impl sync::CompPacket for EcsCompPacket {
|
||||
EcsCompPacket::Mass(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::Gravity(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::Sticky(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::AbilityAction(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::AbilityState(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::AbilityPool(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::Attacking(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::CharacterState(comp) => sync::handle_insert(comp, entity, world),
|
||||
@ -91,7 +91,7 @@ impl sync::CompPacket for EcsCompPacket {
|
||||
EcsCompPacket::Mass(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::Gravity(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::Sticky(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::AbilityAction(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::AbilityState(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::AbilityPool(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::Attacking(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::CharacterState(comp) => sync::handle_modify(comp, entity, world),
|
||||
@ -115,8 +115,8 @@ impl sync::CompPacket for EcsCompPacket {
|
||||
EcsCompPhantom::Mass(_) => sync::handle_remove::<comp::Mass>(entity, world),
|
||||
EcsCompPhantom::Gravity(_) => sync::handle_remove::<comp::Gravity>(entity, world),
|
||||
EcsCompPhantom::Sticky(_) => sync::handle_remove::<comp::Sticky>(entity, world),
|
||||
EcsCompPhantom::AbilityAction(_) => {
|
||||
sync::handle_remove::<comp::AbilityAction>(entity, world)
|
||||
EcsCompPhantom::AbilityState(_) => {
|
||||
sync::handle_remove::<comp::AbilityState>(entity, world)
|
||||
},
|
||||
EcsCompPhantom::AbilityPool(_) => {
|
||||
sync::handle_remove::<comp::AbilityPool>(entity, world)
|
||||
|
@ -107,7 +107,7 @@ impl State {
|
||||
ecs.register_sync_marker();
|
||||
// Register server -> all clients synced components.
|
||||
ecs.register::<comp::AbilityPool>();
|
||||
ecs.register::<comp::AbilityAction>();
|
||||
ecs.register::<comp::AbilityState>();
|
||||
ecs.register::<comp::Projectile>();
|
||||
ecs.register::<comp::Body>();
|
||||
ecs.register::<comp::Player>();
|
||||
|
@ -1,85 +1,72 @@
|
||||
use crate::{
|
||||
comp::{Attacking, CharacterState, EcsStateData, ItemKind::Tool, StateUpdate, ToolData},
|
||||
states::StateHandler,
|
||||
comp::{Attacking, CharacterState, ItemKind::Tool, StateUpdate},
|
||||
states::utils::*,
|
||||
sys::character_state::JoinData,
|
||||
};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State {
|
||||
/// How long the state has until exitting
|
||||
pub remaining_duration: Duration,
|
||||
/// Whether the attack can deal more damage
|
||||
pub exhausted: bool,
|
||||
}
|
||||
pub fn behavior(data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
character: *data.character,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(ecs_data: &EcsStateData) -> Self {
|
||||
let remaining_duration =
|
||||
if let Some(Tool(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| i.kind) {
|
||||
data.attack_duration()
|
||||
} else {
|
||||
Duration::from_millis(300)
|
||||
};
|
||||
Self {
|
||||
remaining_duration,
|
||||
exhausted: false,
|
||||
}
|
||||
}
|
||||
if let CharacterState::BasicAttack {
|
||||
exhausted,
|
||||
remaining_duration,
|
||||
} = data.character
|
||||
{
|
||||
handle_move(data, &mut update);
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
energy: *ecs_data.energy,
|
||||
character: *ecs_data.character,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
let tool_kind = ecs_data.stats.equipment.main.as_ref().map(|i| i.kind);
|
||||
|
||||
let can_apply_damage = !self.exhausted
|
||||
&& if let Some(Tool(data)) = tool_kind {
|
||||
(self.remaining_duration < data.attack_recover_duration())
|
||||
let tool_kind = data.stats.equipment.main.as_ref().map(|i| i.kind);
|
||||
let can_apply_damage = !*exhausted
|
||||
&& if let Some(Tool(tool)) = tool_kind {
|
||||
*remaining_duration < tool.attack_recover_duration()
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
let mut exhausted = self.exhausted;
|
||||
let mut new_exhausted = *exhausted;
|
||||
|
||||
if can_apply_damage {
|
||||
if let Some(Tool(data)) = tool_kind {
|
||||
ecs_data
|
||||
.updater
|
||||
.insert(*ecs_data.entity, Attacking { weapon: Some(data) });
|
||||
if let Some(Tool(tool)) = tool_kind {
|
||||
data.updater
|
||||
.insert(data.entity, Attacking { weapon: Some(tool) });
|
||||
} else {
|
||||
ecs_data
|
||||
.updater
|
||||
.insert(*ecs_data.entity, Attacking { weapon: None });
|
||||
data.updater.insert(data.entity, Attacking { weapon: None });
|
||||
}
|
||||
exhausted = true;
|
||||
new_exhausted = true;
|
||||
} else {
|
||||
ecs_data.updater.remove::<Attacking>(*ecs_data.entity);
|
||||
data.updater.remove::<Attacking>(data.entity);
|
||||
}
|
||||
|
||||
let remaining_duration = self
|
||||
.remaining_duration
|
||||
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
|
||||
let new_remaining_duration = remaining_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default();
|
||||
|
||||
// Tick down
|
||||
update.character = CharacterState::BasicAttack(Some(State {
|
||||
remaining_duration,
|
||||
exhausted,
|
||||
}));
|
||||
update.character = CharacterState::BasicAttack {
|
||||
remaining_duration: new_remaining_duration,
|
||||
exhausted: new_exhausted,
|
||||
};
|
||||
|
||||
// Check if attack duration has expired
|
||||
if remaining_duration == Duration::default() {
|
||||
update.character = CharacterState::Wielded(None);
|
||||
ecs_data.updater.remove::<Attacking>(*ecs_data.entity);
|
||||
if new_remaining_duration == Duration::default() {
|
||||
update.character = if let Some(Tool(tool)) = tool_kind {
|
||||
CharacterState::Wielding { tool }
|
||||
} else {
|
||||
CharacterState::Idle {}
|
||||
};
|
||||
data.updater.remove::<Attacking>(data.entity);
|
||||
}
|
||||
|
||||
update
|
||||
} else {
|
||||
update
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,30 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{CharacterState, EcsStateData, StateUpdate},
|
||||
states::StateHandler,
|
||||
comp::{CharacterEntityData, CharacterState, StateUpdate},
|
||||
};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
use vek::Vec2;
|
||||
use crate::sys::character_state::JoinData;
|
||||
|
||||
const BLOCK_ACCEL: f32 = 30.0;
|
||||
const BLOCK_SPEED: f32 = 75.0;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State {}
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(_ecs_data: &EcsStateData) -> Self { Self {} }
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
pub fn handle(data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
energy: *ecs_data.energy,
|
||||
character: *ecs_data.character,
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
character: *data.character,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
handle_move_dir(&ecs_data, &mut update);
|
||||
handle_move(&data, &mut update);
|
||||
|
||||
if !ecs_data.physics.on_ground || !ecs_data.inputs.secondary.is_pressed() {
|
||||
update.character = CharacterState::Wielded(None);
|
||||
if !data.physics.on_ground || !data.inputs.secondary.is_pressed() {
|
||||
update.character = CharacterState::Wielding{};
|
||||
}
|
||||
|
||||
update
|
||||
|
@ -1,89 +1,62 @@
|
||||
use super::utils::*;
|
||||
use crate::comp::{
|
||||
ActionState::Attack, AttackKind::Charge, EcsStateData, HealthChange, HealthSource,
|
||||
ItemKind::Tool, MoveState::Run, StateUpdate, ToolData,
|
||||
use crate::{
|
||||
comp::{
|
||||
ActionState::Attack, AttackKind::Charge, CharacterEntityData, HealthChange, HealthSource,
|
||||
ItemKind::Tool, MoveState::Run, StateUpdate, ToolData,
|
||||
},
|
||||
event::ServerEvent,
|
||||
sys::character_state::JoinData,
|
||||
};
|
||||
use crate::event::ServerEvent;
|
||||
use crate::states::StateHandler;
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
const CHARGE_SPEED: f32 = 20.0;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State {
|
||||
/// How long the state has until exitting
|
||||
pub remaining_duration: Duration,
|
||||
}
|
||||
pub fn behavior(data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
character: *data.character,
|
||||
};
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(ecs_data: &EcsStateData) -> Self {
|
||||
let tool_data =
|
||||
if let Some(Tool(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| i.kind) {
|
||||
data
|
||||
} else {
|
||||
ToolData::default()
|
||||
};
|
||||
Self {
|
||||
remaining_duration: tool_data.attack_duration(),
|
||||
}
|
||||
// Move player
|
||||
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
|
||||
+ (update.vel.0 * Vec3::new(1.0, 1.0, 0.0)
|
||||
+ 1.5 * data.inputs.move_dir.try_normalized().unwrap_or_default())
|
||||
.try_normalized()
|
||||
.unwrap_or_default()
|
||||
* CHARGE_SPEED;
|
||||
|
||||
// Check if hitting another entity
|
||||
if let Some(uid_b) = data.physics.touch_entity {
|
||||
// Send Damage event
|
||||
data.server_bus.emitter().emit(ServerEvent::Damage {
|
||||
uid: uid_b,
|
||||
change: HealthChange {
|
||||
amount: -20,
|
||||
cause: HealthSource::Attack { by: *data.uid },
|
||||
},
|
||||
});
|
||||
|
||||
// Go back to wielding or idling
|
||||
update.character.action_state = attempt_wield(data.stats);
|
||||
return update;
|
||||
}
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
character: *ecs_data.character,
|
||||
};
|
||||
|
||||
// Prevent move state handling, handled here
|
||||
update.character.move_state = Run(None);
|
||||
|
||||
// Move player
|
||||
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
|
||||
+ (update.vel.0 * Vec3::new(1.0, 1.0, 0.0)
|
||||
+ 1.5
|
||||
* ecs_data
|
||||
.inputs
|
||||
.move_dir
|
||||
.try_normalized()
|
||||
.unwrap_or_default())
|
||||
.try_normalized()
|
||||
.unwrap_or_default()
|
||||
* CHARGE_SPEED;
|
||||
|
||||
// Check if hitting another entity
|
||||
if let Some(uid_b) = ecs_data.physics.touch_entity {
|
||||
// Send Damage event
|
||||
ecs_data.server_bus.emitter().emit(ServerEvent::Damage {
|
||||
uid: uid_b,
|
||||
change: HealthChange {
|
||||
amount: -20,
|
||||
cause: HealthSource::Attack { by: *ecs_data.uid },
|
||||
},
|
||||
});
|
||||
|
||||
// Go back to wielding or idling
|
||||
update.character.action_state = attempt_wield(ecs_data.stats);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Check if charge timed out or can't keep moving forward
|
||||
if self.remaining_duration == Duration::default() || update.vel.0.magnitude_squared() < 10.0
|
||||
{
|
||||
update.character.action_state = attempt_wield(ecs_data.stats);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Tick remaining-duration and keep charging
|
||||
update.character.action_state = Attack(Charge(Some(State {
|
||||
remaining_duration: self
|
||||
.remaining_duration
|
||||
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
})));
|
||||
|
||||
update
|
||||
// Check if charge timed out or can't keep moving forward
|
||||
if self.remaining_duration == Duration::default() || update.vel.0.magnitude_squared() < 10.0 {
|
||||
update.character.action_state = attempt_wield(data.stats);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Tick remaining-duration and keep charging
|
||||
update.character.action_state = Attack(Charge(Some(State {
|
||||
remaining_duration: self
|
||||
.remaining_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
})));
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{CharacterState, EcsStateData, EnergySource, StateUpdate},
|
||||
states::StateHandler,
|
||||
sys::phys::GRAVITY,
|
||||
comp::{CharacterState, EnergySource, StateUpdate},
|
||||
event::LocalEvent,
|
||||
sys::{character_state::JoinData, phys::GRAVITY},
|
||||
};
|
||||
use std::collections::VecDeque;
|
||||
use vek::{
|
||||
@ -12,91 +12,84 @@ use vek::{
|
||||
const HUMANOID_CLIMB_ACCEL: f32 = 5.0;
|
||||
const CLIMB_SPEED: f32 = 5.0;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State;
|
||||
pub fn behavior(data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
character: *data.character,
|
||||
energy: *data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(_ecs_data: &EcsStateData) -> Self { Self {} }
|
||||
if let Err(_) = update.energy.try_change_by(-5, EnergySource::Climb) {
|
||||
update.character = CharacterState::Idle {};
|
||||
}
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
character: *ecs_data.character,
|
||||
energy: *ecs_data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
// If no wall is in front of character ...
|
||||
if data.physics.on_wall.is_none() || data.physics.on_ground {
|
||||
if data.inputs.jump.is_pressed() {
|
||||
// They've climbed atop something, give them a boost
|
||||
update
|
||||
.local_events
|
||||
.push_front(LocalEvent::Jump(data.entity));
|
||||
}
|
||||
update.character = CharacterState::Idle {};
|
||||
return update;
|
||||
}
|
||||
|
||||
// Move player
|
||||
update.vel.0 += Vec2::broadcast(data.dt.0)
|
||||
* data.inputs.move_dir
|
||||
* if update.vel.0.magnitude_squared() < CLIMB_SPEED.powf(2.0) {
|
||||
HUMANOID_CLIMB_ACCEL
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
if let Err(_) = update.energy.try_change_by(-5, EnergySource::Climb) {
|
||||
update.character = CharacterState::Idle(None);
|
||||
}
|
||||
|
||||
// If no wall is in front of character ...
|
||||
if ecs_data.physics.on_wall.is_none() || ecs_data.physics.on_ground {
|
||||
if ecs_data.inputs.jump.is_pressed() {
|
||||
// They've climbed atop something, give them a boost
|
||||
//TODO: JUMP EVENT
|
||||
}
|
||||
update.character = CharacterState::Idle(None);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Move player
|
||||
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
|
||||
* ecs_data.inputs.move_dir
|
||||
* if update.vel.0.magnitude_squared() < CLIMB_SPEED.powf(2.0) {
|
||||
HUMANOID_CLIMB_ACCEL
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
// Set orientation direction based on wall direction
|
||||
let ori_dir = if let Some(wall_dir) = ecs_data.physics.on_wall {
|
||||
if Vec2::<f32>::from(wall_dir).magnitude_squared() > 0.001 {
|
||||
Vec2::from(wall_dir).normalized()
|
||||
} else {
|
||||
Vec2::from(update.vel.0)
|
||||
}
|
||||
// Set orientation direction based on wall direction
|
||||
let ori_dir = if let Some(wall_dir) = data.physics.on_wall {
|
||||
if Vec2::<f32>::from(wall_dir).magnitude_squared() > 0.001 {
|
||||
Vec2::from(wall_dir).normalized()
|
||||
} else {
|
||||
Vec2::from(update.vel.0)
|
||||
};
|
||||
}
|
||||
} else {
|
||||
Vec2::from(update.vel.0)
|
||||
};
|
||||
|
||||
// Smooth orientation
|
||||
if ori_dir.magnitude_squared() > 0.0001
|
||||
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
|
||||
> 0.001
|
||||
{
|
||||
update.ori.0 = vek::ops::Slerp::slerp(
|
||||
update.ori.0,
|
||||
ori_dir.into(),
|
||||
if ecs_data.physics.on_ground { 9.0 } else { 2.0 } * ecs_data.dt.0,
|
||||
// Smooth orientation
|
||||
if ori_dir.magnitude_squared() > 0.0001
|
||||
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
|
||||
> 0.001
|
||||
{
|
||||
update.ori.0 = vek::ops::Slerp::slerp(
|
||||
update.ori.0,
|
||||
ori_dir.into(),
|
||||
if data.physics.on_ground { 9.0 } else { 2.0 } * data.dt.0,
|
||||
);
|
||||
}
|
||||
|
||||
// Apply Vertical Climbing Movement
|
||||
if let (true, Some(_wall_dir)) = (
|
||||
(data.inputs.climb.is_pressed() | data.inputs.climb_down.is_pressed())
|
||||
&& update.vel.0.z <= CLIMB_SPEED,
|
||||
data.physics.on_wall,
|
||||
) {
|
||||
if data.inputs.climb_down.is_pressed() && !data.inputs.climb.is_pressed() {
|
||||
update.vel.0 -= data.dt.0 * update.vel.0.map(|e| e.abs().powf(1.5) * e.signum() * 6.0);
|
||||
} else if data.inputs.climb.is_pressed() && !data.inputs.climb_down.is_pressed() {
|
||||
update.vel.0.z = (update.vel.0.z + data.dt.0 * GRAVITY * 1.25).min(CLIMB_SPEED);
|
||||
} else {
|
||||
update.vel.0.z = update.vel.0.z + data.dt.0 * GRAVITY * 1.5;
|
||||
update.vel.0 = Lerp::lerp(
|
||||
update.vel.0,
|
||||
Vec3::zero(),
|
||||
30.0 * data.dt.0 / (1.0 - update.vel.0.z.min(0.0) * 5.0),
|
||||
);
|
||||
}
|
||||
|
||||
// Apply Vertical Climbing Movement
|
||||
if let (true, Some(_wall_dir)) = (
|
||||
(ecs_data.inputs.climb.is_pressed() | ecs_data.inputs.climb_down.is_pressed())
|
||||
&& update.vel.0.z <= CLIMB_SPEED,
|
||||
ecs_data.physics.on_wall,
|
||||
) {
|
||||
if ecs_data.inputs.climb_down.is_pressed() && !ecs_data.inputs.climb.is_pressed() {
|
||||
update.vel.0 -=
|
||||
ecs_data.dt.0 * update.vel.0.map(|e| e.abs().powf(1.5) * e.signum() * 6.0);
|
||||
} else if ecs_data.inputs.climb.is_pressed() && !ecs_data.inputs.climb_down.is_pressed()
|
||||
{
|
||||
update.vel.0.z = (update.vel.0.z + ecs_data.dt.0 * GRAVITY * 1.25).min(CLIMB_SPEED);
|
||||
} else {
|
||||
update.vel.0.z = update.vel.0.z + ecs_data.dt.0 * GRAVITY * 1.5;
|
||||
update.vel.0 = Lerp::lerp(
|
||||
update.vel.0,
|
||||
Vec3::zero(),
|
||||
30.0 * ecs_data.dt.0 / (1.0 - update.vel.0.z.min(0.0) * 5.0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
|
38
common/src/states/equipping.rs
Normal file
38
common/src/states/equipping.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{CharacterState, StateUpdate},
|
||||
sys::character_state::JoinData,
|
||||
};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
|
||||
pub fn behavior(data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *data.character,
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
handle_move(&data, &mut update);
|
||||
handle_jump(&data, &mut update);
|
||||
|
||||
if let CharacterState::Equipping { tool, time_left } = data.character {
|
||||
if *time_left == Duration::default() {
|
||||
// Wield delay has expired
|
||||
update.character = CharacterState::Wielding { tool: *tool };
|
||||
} else {
|
||||
// Wield delay hasn't expired yet
|
||||
// Update wield delay
|
||||
update.character = CharacterState::Equipping {
|
||||
time_left: time_left
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
tool: *tool,
|
||||
};
|
||||
}
|
||||
}
|
||||
update
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use crate::comp::{ActionState, EcsStateData, MoveState, StateUpdate};
|
||||
use crate::comp::{ActionState, CharacterEntityData, MoveState, StateUpdate};
|
||||
|
||||
use super::utils::*;
|
||||
use crate::states::StateHandler;
|
||||
@ -11,11 +11,9 @@ const HUMANOID_AIR_SPEED: f32 = 100.0;
|
||||
pub struct State;
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(_ecs_data: &EcsStateData) -> Self {
|
||||
Self {}
|
||||
}
|
||||
fn new(_ecs_data: &CharacterEntityData) -> Self { Self {} }
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
fn handle(&self, ecs_data: &CharacterEntityData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
comp::{CharacterState, EcsStateData, StateUpdate},
|
||||
states::StateHandler,
|
||||
comp::{CharacterState, StateUpdate},
|
||||
sys::character_state::JoinData,
|
||||
};
|
||||
use std::collections::VecDeque;
|
||||
use vek::{Vec2, Vec3};
|
||||
@ -10,65 +10,57 @@ const GLIDE_ANTIGRAV: f32 = crate::sys::phys::GRAVITY * 0.96;
|
||||
const GLIDE_ACCEL: f32 = 15.0;
|
||||
const GLIDE_SPEED: f32 = 45.0;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State;
|
||||
pub fn behavior(data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
character: *data.character,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(_ecs_data: &EcsStateData) -> Self { Self {} }
|
||||
// If glide button isn't held or player is on ground, end glide
|
||||
if !data.inputs.glide.is_pressed() || data.physics.on_ground {
|
||||
update.character = CharacterState::Idle {};
|
||||
}
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
energy: *ecs_data.energy,
|
||||
character: *ecs_data.character,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
// If there is a wall in front of character go to climb
|
||||
if let Some(_) = data.physics.on_wall {
|
||||
update.character = CharacterState::Climb {};
|
||||
}
|
||||
|
||||
// Move player according to movement direction vector
|
||||
update.vel.0 += Vec2::broadcast(data.dt.0)
|
||||
* data.inputs.move_dir
|
||||
* if data.vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) {
|
||||
GLIDE_ACCEL
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
// If glide button isn't held or player is on ground, end glide
|
||||
if !ecs_data.inputs.glide.is_pressed() || ecs_data.physics.on_ground {
|
||||
update.character = CharacterState::Idle(None);
|
||||
}
|
||||
|
||||
// If there is a wall in front of character go to climb
|
||||
if let Some(_) = ecs_data.physics.on_wall {
|
||||
update.character = CharacterState::Climb(None);
|
||||
}
|
||||
|
||||
// Move player according to movement direction vector
|
||||
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
|
||||
* ecs_data.inputs.move_dir
|
||||
* if ecs_data.vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) {
|
||||
GLIDE_ACCEL
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
// Determine orientation vector from movement direction vector
|
||||
let ori_dir = Vec2::from(update.vel.0);
|
||||
if ori_dir.magnitude_squared() > 0.0001
|
||||
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
|
||||
> 0.001
|
||||
{
|
||||
update.ori.0 =
|
||||
vek::ops::Slerp::slerp(update.ori.0, ori_dir.into(), 2.0 * ecs_data.dt.0);
|
||||
}
|
||||
|
||||
// Apply Glide antigrav lift
|
||||
if Vec2::<f32>::from(update.vel.0).magnitude_squared() < GLIDE_SPEED.powf(2.0)
|
||||
&& update.vel.0.z < 0.0
|
||||
{
|
||||
let lift = GLIDE_ANTIGRAV + update.vel.0.z.abs().powf(2.0) * 0.15;
|
||||
update.vel.0.z += ecs_data.dt.0
|
||||
* lift
|
||||
* (Vec2::<f32>::from(update.vel.0).magnitude() * 0.075)
|
||||
.min(1.0)
|
||||
.max(0.2);
|
||||
}
|
||||
|
||||
// Otherwise keep gliding
|
||||
update
|
||||
// Determine orientation vector from movement direction vector
|
||||
let ori_dir = Vec2::from(update.vel.0);
|
||||
if ori_dir.magnitude_squared() > 0.0001
|
||||
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
|
||||
> 0.001
|
||||
{
|
||||
update.ori.0 = vek::ops::Slerp::slerp(update.ori.0, ori_dir.into(), 2.0 * data.dt.0);
|
||||
}
|
||||
|
||||
// Apply Glide antigrav lift
|
||||
if Vec2::<f32>::from(update.vel.0).magnitude_squared() < GLIDE_SPEED.powf(2.0)
|
||||
&& update.vel.0.z < 0.0
|
||||
{
|
||||
let lift = GLIDE_ANTIGRAV + update.vel.0.z.abs().powf(2.0) * 0.15;
|
||||
update.vel.0.z += data.dt.0
|
||||
* lift
|
||||
* (Vec2::<f32>::from(update.vel.0).magnitude() * 0.075)
|
||||
.min(1.0)
|
||||
.max(0.2);
|
||||
}
|
||||
|
||||
// Otherwise keep gliding
|
||||
update
|
||||
}
|
||||
|
@ -1,33 +1,24 @@
|
||||
use super::utils::*;
|
||||
use crate::comp::{EcsStateData, StateUpdate};
|
||||
use crate::{comp::StateUpdate, sys::character_state::JoinData};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::states::StateHandler;
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State;
|
||||
pub fn behavior(data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *data.character,
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
handle_move(data, &mut update);
|
||||
handle_jump(data, &mut update);
|
||||
handle_wield(data, &mut update);
|
||||
handle_sit(data, &mut update);
|
||||
handle_climb(data, &mut update);
|
||||
handle_glide(data, &mut update);
|
||||
handle_dodge(data, &mut update);
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(_ecs_data: &EcsStateData) -> Self { Self {} }
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
energy: *ecs_data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
handle_move_dir(ecs_data, &mut update);
|
||||
handle_jump(ecs_data, &mut update);
|
||||
handle_wield(ecs_data, &mut update);
|
||||
handle_sit(ecs_data, &mut update);
|
||||
handle_climb(ecs_data, &mut update);
|
||||
handle_glide(ecs_data, &mut update);
|
||||
handle_dodge(ecs_data, &mut update);
|
||||
|
||||
update
|
||||
}
|
||||
update
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
use super::{EcsStateData, MoveState, StateHandler, StateUpdate};
|
||||
use super::{CharacterEntityData, MoveState, StateHandler, StateUpdate};
|
||||
use crate::event::LocalEvent;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State;
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(_ecs_data: &EcsStateData) -> Self {
|
||||
Self {}
|
||||
}
|
||||
fn new(_ecs_data: &CharacterEntityData) -> Self { Self {} }
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
fn handle(&self, ecs_data: &CharacterEntityData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
|
@ -1,28 +1,11 @@
|
||||
// Module declarations
|
||||
pub mod basic_attack;
|
||||
pub mod basic_block;
|
||||
// pub mod basic_block;
|
||||
pub mod climb;
|
||||
pub mod equipping;
|
||||
pub mod glide;
|
||||
pub mod idle;
|
||||
pub mod roll;
|
||||
pub mod sit;
|
||||
pub mod utils;
|
||||
pub mod wielded;
|
||||
pub mod wielding;
|
||||
|
||||
use crate::comp::{EcsStateData, StateUpdate};
|
||||
|
||||
/// ## A type for implementing State Handling Behavior.
|
||||
///
|
||||
/// Called by state machines' update functions to allow current states to handle
|
||||
/// updating their parent machine's current state.
|
||||
///
|
||||
/// Structures must implement a `handle()` fn to handle update behavior, and a
|
||||
/// `new()` for instantiating new instances of a state. `handle()` function
|
||||
/// recieves `EcsStateData`, a struct of readonly ECS Component data, and
|
||||
/// returns a `StateUpdate` tuple, with new components that will overwrite an
|
||||
/// entitie's old components.
|
||||
pub trait StateHandler: Default {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate;
|
||||
fn new(ecs_data: &EcsStateData) -> Self;
|
||||
}
|
||||
|
@ -1,51 +1,28 @@
|
||||
use crate::{
|
||||
comp::{CharacterState, EcsStateData, ItemKind::Tool, StateUpdate, ToolData},
|
||||
states::StateHandler,
|
||||
comp::{CharacterState, StateUpdate},
|
||||
sys::character_state::JoinData,
|
||||
};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
use vek::Vec3;
|
||||
|
||||
const ROLL_SPEED: f32 = 17.0;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State {
|
||||
/// How long the state has until exitting
|
||||
remaining_duration: Duration,
|
||||
}
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(ecs_data: &EcsStateData) -> Self {
|
||||
let tool_data =
|
||||
if let Some(Tool(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| i.kind) {
|
||||
data
|
||||
} else {
|
||||
ToolData::default()
|
||||
};
|
||||
Self {
|
||||
remaining_duration: tool_data.attack_duration(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
energy: *ecs_data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
pub fn behavior(data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *data.character,
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
if let CharacterState::Roll { remaining_duration } = data.character {
|
||||
// Update velocity
|
||||
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
|
||||
+ (update.vel.0 * Vec3::new(1.0, 1.0, 0.0)
|
||||
+ 1.5
|
||||
* ecs_data
|
||||
.inputs
|
||||
.move_dir
|
||||
.try_normalized()
|
||||
.unwrap_or_default())
|
||||
+ 1.5 * data.inputs.move_dir.try_normalized().unwrap_or_default())
|
||||
.try_normalized()
|
||||
.unwrap_or_default()
|
||||
* ROLL_SPEED;
|
||||
@ -57,22 +34,21 @@ impl StateHandler for State {
|
||||
> 0.001
|
||||
{
|
||||
update.ori.0 =
|
||||
vek::ops::Slerp::slerp(update.ori.0, update.vel.0.into(), 9.0 * ecs_data.dt.0);
|
||||
vek::ops::Slerp::slerp(update.ori.0, update.vel.0.into(), 9.0 * data.dt.0);
|
||||
}
|
||||
|
||||
if self.remaining_duration == Duration::default() {
|
||||
if *remaining_duration == Duration::default() {
|
||||
// Roll duration has expired
|
||||
update.character = CharacterState::Idle(None);
|
||||
update.character = CharacterState::Idle {};
|
||||
} else {
|
||||
// Otherwise, tick down remaining_duration
|
||||
update.character = CharacterState::Roll(Some(State {
|
||||
remaining_duration: self
|
||||
.remaining_duration
|
||||
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
|
||||
update.character = CharacterState::Roll {
|
||||
remaining_duration: remaining_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -1,38 +1,30 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{CharacterState, EcsStateData, StateUpdate},
|
||||
states::StateHandler,
|
||||
comp::{CharacterState, StateUpdate},
|
||||
sys::character_state::JoinData,
|
||||
};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State;
|
||||
pub fn behavior(data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *data.character,
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(_ecs_data: &EcsStateData) -> Self { Self {} }
|
||||
handle_wield(data, &mut update);
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
energy: *ecs_data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
//handle_jump(ecs_data, &mut update);
|
||||
handle_wield(ecs_data, &mut update);
|
||||
|
||||
// Try to Fall/Stand up/Move
|
||||
if !ecs_data.physics.on_ground
|
||||
|| ecs_data.inputs.sit.is_just_pressed()
|
||||
|| ecs_data.inputs.move_dir.magnitude_squared() > 0.0
|
||||
{
|
||||
update.character = CharacterState::Idle(None);
|
||||
}
|
||||
|
||||
update
|
||||
// Try to Fall/Stand up/Move
|
||||
if !data.physics.on_ground
|
||||
|| data.inputs.sit.is_just_pressed()
|
||||
|| data.inputs.move_dir.magnitude_squared() > 0.0
|
||||
{
|
||||
update.character = CharacterState::Idle {};
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
use super::utils::*;
|
||||
use crate::comp::{EcsStateData, MoveState, StateUpdate};
|
||||
use crate::states::StateHandler;
|
||||
use crate::{
|
||||
comp::{CharacterEntityData, MoveState, StateUpdate},
|
||||
states::StateHandler,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State;
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(_ecs_data: &EcsStateData) -> Self {
|
||||
Self {}
|
||||
}
|
||||
fn new(_ecs_data: &CharacterEntityData) -> Self { Self {} }
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
fn handle(&self, ecs_data: &CharacterEntityData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
|
@ -1,82 +1,56 @@
|
||||
use crate::comp::{ActionState, EcsStateData, MoveState, StateUpdate};
|
||||
use crate::states::StateHandler;
|
||||
use crate::sys::phys::GRAVITY;
|
||||
use crate::{
|
||||
comp::StateUpdate,
|
||||
sys::{character_state::JoinData, phys::GRAVITY},
|
||||
};
|
||||
use std::time::Duration;
|
||||
use vek::{Vec2, Vec3};
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State;
|
||||
|
||||
const HUMANOID_WATER_ACCEL: f32 = 70.0;
|
||||
const HUMANOID_WATER_SPEED: f32 = 120.0;
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(_ecs_data: &EcsStateData) -> Self {
|
||||
Self {}
|
||||
}
|
||||
pub fn behavior(data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *data.character,
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
// Update velocity
|
||||
update.vel.0 += Vec2::broadcast(data.dt.0)
|
||||
* data.inputs.move_dir
|
||||
* if update.vel.0.magnitude_squared() < HUMANOID_WATER_SPEED.powf(2.0) {
|
||||
HUMANOID_WATER_ACCEL
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
// Update velocity
|
||||
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
|
||||
* ecs_data.inputs.move_dir
|
||||
* if update.vel.0.magnitude_squared() < HUMANOID_WATER_SPEED.powf(2.0) {
|
||||
HUMANOID_WATER_ACCEL
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
// Set direction based on move direction when on the ground
|
||||
let ori_dir = if update.character.is_attack() || update.character.is_block() {
|
||||
Vec2::from(data.inputs.look_dir).normalized()
|
||||
} else {
|
||||
Vec2::from(update.vel.0)
|
||||
};
|
||||
|
||||
// Set direction based on move direction when on the ground
|
||||
let ori_dir =
|
||||
if let ActionState::Attack(_) | ActionState::Block(_) = update.character.action_state {
|
||||
Vec2::from(ecs_data.inputs.look_dir).normalized()
|
||||
} else {
|
||||
Vec2::from(update.vel.0)
|
||||
};
|
||||
|
||||
if ori_dir.magnitude_squared() > 0.0001
|
||||
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
|
||||
> 0.001
|
||||
{
|
||||
update.ori.0 = vek::ops::Slerp::slerp(
|
||||
update.ori.0,
|
||||
ori_dir.into(),
|
||||
if ecs_data.physics.on_ground { 9.0 } else { 2.0 } * ecs_data.dt.0,
|
||||
);
|
||||
}
|
||||
|
||||
// Force players to press jump in a slow rhythmic fashion to swim up
|
||||
if ecs_data.inputs.jump.is_pressed()
|
||||
&& !ecs_data
|
||||
.inputs
|
||||
.jump
|
||||
.is_long_press(Duration::from_millis(600))
|
||||
{
|
||||
update.vel.0.z =
|
||||
(update.vel.0.z + ecs_data.dt.0 * GRAVITY * 1.25).min(HUMANOID_WATER_SPEED);
|
||||
}
|
||||
|
||||
// Not on ground
|
||||
if !ecs_data.physics.on_ground {
|
||||
update.character.move_state = MoveState::Swim(None);
|
||||
update
|
||||
}
|
||||
// On ground
|
||||
else {
|
||||
// Return to running or standing based on move inputs
|
||||
update.character.move_state = if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
|
||||
MoveState::Run(None)
|
||||
} else {
|
||||
MoveState::Stand(None)
|
||||
};
|
||||
|
||||
update
|
||||
}
|
||||
if ori_dir.magnitude_squared() > 0.0001
|
||||
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
|
||||
> 0.001
|
||||
{
|
||||
update.ori.0 = vek::ops::Slerp::slerp(
|
||||
update.ori.0,
|
||||
ori_dir.into(),
|
||||
if data.physics.on_ground { 9.0 } else { 2.0 } * data.dt.0,
|
||||
);
|
||||
}
|
||||
|
||||
// Force players to pulse jump button to swim up
|
||||
if data.inputs.jump.is_pressed() && !data.inputs.jump.is_long_press(Duration::from_millis(600))
|
||||
{
|
||||
update.vel.0.z = (update.vel.0.z + data.dt.0 * GRAVITY * 1.25).min(HUMANOID_WATER_SPEED);
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -1,12 +1,24 @@
|
||||
use crate::{
|
||||
comp::{Attacking, CharacterState, EcsStateData, EnergySource, ItemKind::Tool, StateUpdate},
|
||||
comp::{AbilityState, CharacterState, EnergySource, ItemKind::Tool, StateUpdate},
|
||||
event::LocalEvent,
|
||||
sys::{character_state::JoinData, phys::GRAVITY},
|
||||
};
|
||||
use std::time::Duration;
|
||||
use vek::vec::{Vec2, Vec3};
|
||||
|
||||
pub fn handle_move_dir(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
let (accel, speed): (f32, f32) = if ecs_data.physics.on_ground {
|
||||
const HUMANOID_WATER_ACCEL: f32 = 70.0;
|
||||
const HUMANOID_WATER_SPEED: f32 = 120.0;
|
||||
|
||||
pub fn handle_move(data: &JoinData, update: &mut StateUpdate) {
|
||||
if data.physics.in_fluid {
|
||||
handle_swim_move(data, update);
|
||||
} else {
|
||||
handle_ground_move(data, update);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_ground_move(data: &JoinData, update: &mut StateUpdate) {
|
||||
let (accel, speed): (f32, f32) = if data.physics.on_ground {
|
||||
let accel = 100.0;
|
||||
let speed = 8.0;
|
||||
(accel, speed)
|
||||
@ -18,8 +30,7 @@ pub fn handle_move_dir(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
|
||||
// Move player according to move_dir
|
||||
if update.vel.0.magnitude_squared() < speed.powf(2.0) {
|
||||
update.vel.0 =
|
||||
update.vel.0 + Vec2::broadcast(ecs_data.dt.0) * ecs_data.inputs.move_dir * accel;
|
||||
update.vel.0 = update.vel.0 + Vec2::broadcast(data.dt.0) * data.inputs.move_dir * accel;
|
||||
let mag2 = update.vel.0.magnitude_squared();
|
||||
if mag2 > speed.powf(2.0) {
|
||||
update.vel.0 = update.vel.0.normalized() * speed;
|
||||
@ -31,7 +42,7 @@ pub fn handle_move_dir(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
|| update.character.is_attack()
|
||||
|| update.character.is_block()
|
||||
{
|
||||
Vec2::from(ecs_data.inputs.look_dir).normalized()
|
||||
Vec2::from(data.inputs.look_dir).normalized()
|
||||
} else {
|
||||
Vec2::from(update.vel.0)
|
||||
};
|
||||
@ -41,94 +52,165 @@ pub fn handle_move_dir(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
|
||||
> 0.001
|
||||
{
|
||||
update.ori.0 = vek::ops::Slerp::slerp(update.ori.0, ori_dir.into(), 9.0 * ecs_data.dt.0);
|
||||
update.ori.0 = vek::ops::Slerp::slerp(update.ori.0, ori_dir.into(), 9.0 * data.dt.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_wield(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
if ecs_data.inputs.primary.is_pressed() {
|
||||
update.character = CharacterState::Wielding(None);
|
||||
}
|
||||
}
|
||||
pub fn handle_swim_move(data: &JoinData, update: &mut StateUpdate) {
|
||||
// Update velocity
|
||||
update.vel.0 += Vec2::broadcast(data.dt.0)
|
||||
* data.inputs.move_dir
|
||||
* if update.vel.0.magnitude_squared() < HUMANOID_WATER_SPEED.powf(2.0) {
|
||||
HUMANOID_WATER_ACCEL
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
pub fn handle_sit(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
if ecs_data.inputs.sit.is_pressed() && ecs_data.physics.on_ground && ecs_data.body.is_humanoid()
|
||||
// Set direction based on move direction when on the ground
|
||||
let ori_dir = if update.character.is_attack() || update.character.is_block() {
|
||||
Vec2::from(data.inputs.look_dir).normalized()
|
||||
} else {
|
||||
Vec2::from(update.vel.0)
|
||||
};
|
||||
|
||||
if ori_dir.magnitude_squared() > 0.0001
|
||||
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
|
||||
> 0.001
|
||||
{
|
||||
update.character = CharacterState::Sit(None);
|
||||
update.ori.0 = vek::ops::Slerp::slerp(
|
||||
update.ori.0,
|
||||
ori_dir.into(),
|
||||
if data.physics.on_ground { 9.0 } else { 2.0 } * data.dt.0,
|
||||
);
|
||||
}
|
||||
|
||||
// Force players to pulse jump button to swim up
|
||||
if data.inputs.jump.is_pressed() && !data.inputs.jump.is_long_press(Duration::from_millis(600))
|
||||
{
|
||||
update.vel.0.z = (update.vel.0.z + data.dt.0 * GRAVITY * 1.25).min(HUMANOID_WATER_SPEED);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_climb(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
if (ecs_data.inputs.climb.is_pressed() || ecs_data.inputs.climb_down.is_pressed())
|
||||
&& ecs_data.physics.on_wall.is_some()
|
||||
&& !ecs_data.physics.on_ground
|
||||
pub fn handle_wield(data: &JoinData, update: &mut StateUpdate) {
|
||||
if data.inputs.primary.is_pressed() {
|
||||
if let Some(Tool(tool)) = data.stats.equipment.main.as_ref().map(|i| i.kind) {
|
||||
update.character = CharacterState::Equipping {
|
||||
tool,
|
||||
time_left: tool.equip_time(),
|
||||
};
|
||||
} else {
|
||||
update.character = CharacterState::Idle {};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_sit(data: &JoinData, update: &mut StateUpdate) {
|
||||
if data.inputs.sit.is_pressed() && data.physics.on_ground && data.body.is_humanoid() {
|
||||
update.character = CharacterState::Sit {};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_climb(data: &JoinData, update: &mut StateUpdate) {
|
||||
if (data.inputs.climb.is_pressed() || data.inputs.climb_down.is_pressed())
|
||||
&& data.physics.on_wall.is_some()
|
||||
&& !data.physics.on_ground
|
||||
//&& update.vel.0.z < 0.0
|
||||
&& ecs_data.body.is_humanoid()
|
||||
&& data.body.is_humanoid()
|
||||
{
|
||||
update.character = CharacterState::Climb(None);
|
||||
update.character = CharacterState::Climb {};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_unwield(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
if let CharacterState::Wielded(_) = update.character {
|
||||
if ecs_data.inputs.toggle_wield.is_pressed() {
|
||||
update.character = CharacterState::Idle(None);
|
||||
pub fn handle_unwield(data: &JoinData, update: &mut StateUpdate) {
|
||||
if let CharacterState::Wielding { .. } = update.character {
|
||||
if data.inputs.toggle_wield.is_pressed() {
|
||||
update.character = CharacterState::Idle {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_glide(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
if let CharacterState::Idle(_) | CharacterState::Wielded(_) = update.character {
|
||||
if ecs_data.inputs.glide.is_pressed()
|
||||
&& !ecs_data.physics.on_ground
|
||||
&& ecs_data.body.is_humanoid()
|
||||
{
|
||||
update.character = CharacterState::Glide(None);
|
||||
pub fn handle_glide(data: &JoinData, update: &mut StateUpdate) {
|
||||
if let CharacterState::Idle { .. } | CharacterState::Wielding { .. } = update.character {
|
||||
if data.inputs.glide.is_pressed() && !data.physics.on_ground && data.body.is_humanoid() {
|
||||
update.character = CharacterState::Glide {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_jump(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
if ecs_data.inputs.jump.is_pressed() && ecs_data.physics.on_ground {
|
||||
pub fn handle_jump(data: &JoinData, update: &mut StateUpdate) {
|
||||
if data.inputs.jump.is_pressed() && data.physics.on_ground {
|
||||
update
|
||||
.local_events
|
||||
.push_front(LocalEvent::Jump(*ecs_data.entity));
|
||||
.push_front(LocalEvent::Jump(data.entity));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_primary(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
if let Some(state) = ecs_data.ability_pool.primary {
|
||||
if let CharacterState::Wielded(_) = update.character {
|
||||
if ecs_data.inputs.primary.is_pressed() {
|
||||
update.character = state;
|
||||
pub fn handle_primary(data: &JoinData, update: &mut StateUpdate) {
|
||||
if let Some(state) = data.ability_pool.primary {
|
||||
if let CharacterState::Wielding { .. } = update.character {
|
||||
if data.inputs.primary.is_pressed() {
|
||||
// data.updater.insert(data.entity, state);
|
||||
update.character = character_state_from_ability(data, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_secondary(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
if let Some(state) = ecs_data.ability_pool.secondary {
|
||||
if let CharacterState::Wielded(_) = update.character {
|
||||
if ecs_data.inputs.secondary.is_pressed() {
|
||||
update.character = state;
|
||||
pub fn handle_secondary(data: &JoinData, update: &mut StateUpdate) {
|
||||
if let Some(state) = data.ability_pool.secondary {
|
||||
if let CharacterState::Wielding { .. } = update.character {
|
||||
if data.inputs.secondary.is_pressed() {
|
||||
// data.updater.insert(data.entity, state);
|
||||
update.character = character_state_from_ability(data, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_dodge(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
if let Some(state) = ecs_data.ability_pool.dodge {
|
||||
if let CharacterState::Idle(_) | CharacterState::Wielded(_) = update.character {
|
||||
if ecs_data.inputs.roll.is_pressed()
|
||||
&& ecs_data.physics.on_ground
|
||||
&& ecs_data.body.is_humanoid()
|
||||
pub fn handle_dodge(data: &JoinData, update: &mut StateUpdate) {
|
||||
if let Some(state) = data.ability_pool.dodge {
|
||||
if let CharacterState::Idle { .. } | CharacterState::Wielding { .. } = update.character {
|
||||
if data.inputs.roll.is_pressed()
|
||||
&& data.physics.on_ground
|
||||
&& data.body.is_humanoid()
|
||||
&& update
|
||||
.energy
|
||||
.try_change_by(-200, EnergySource::Roll)
|
||||
.is_ok()
|
||||
{
|
||||
update.character = state;
|
||||
// let tool_data =
|
||||
// if let Some(Tool(data)) = data.stats.equipment.main.as_ref().map(|i|
|
||||
// i.kind) { data
|
||||
// } else {
|
||||
// ToolData::default()
|
||||
// };
|
||||
update.character = CharacterState::Roll {
|
||||
remaining_duration: Duration::from_millis(600), // tool_data.attack_duration(),
|
||||
};
|
||||
data.updater.insert(data.entity, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn character_state_from_ability(
|
||||
data: &JoinData,
|
||||
ability_state: AbilityState,
|
||||
) -> CharacterState {
|
||||
match ability_state {
|
||||
AbilityState::BasicAttack { .. } => {
|
||||
if let Some(Tool(tool)) = data.stats.equipment.main.as_ref().map(|i| i.kind) {
|
||||
CharacterState::BasicAttack {
|
||||
exhausted: false,
|
||||
remaining_duration: tool.attack_duration(),
|
||||
}
|
||||
} else {
|
||||
CharacterState::Idle {}
|
||||
}
|
||||
},
|
||||
AbilityState::BasicBlock { .. } => CharacterState::BasicBlock {},
|
||||
AbilityState::Roll { .. } => CharacterState::Roll {
|
||||
remaining_duration: Duration::from_millis(600),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{EcsStateData, ItemKind::Tool, StateUpdate, ToolData},
|
||||
states::StateHandler,
|
||||
};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State {
|
||||
/// How long before a new action can be performed
|
||||
/// after equipping
|
||||
pub equip_delay: Duration,
|
||||
}
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(ecs_data: &EcsStateData) -> Self {
|
||||
let tool_data =
|
||||
if let Some(Tool(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| i.kind) {
|
||||
data
|
||||
} else {
|
||||
ToolData::default()
|
||||
};
|
||||
Self {
|
||||
equip_delay: tool_data.equip_time(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
energy: *ecs_data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
handle_move_dir(&ecs_data, &mut update);
|
||||
handle_jump(&ecs_data, &mut update);
|
||||
handle_sit(&ecs_data, &mut update);
|
||||
handle_climb(&ecs_data, &mut update);
|
||||
handle_glide(&ecs_data, &mut update);
|
||||
handle_unwield(&ecs_data, &mut update);
|
||||
handle_primary(&ecs_data, &mut update);
|
||||
handle_secondary(&ecs_data, &mut update);
|
||||
handle_dodge(&ecs_data, &mut update);
|
||||
|
||||
update
|
||||
}
|
||||
}
|
@ -1,56 +1,27 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{CharacterState, EcsStateData, ItemKind::Tool, StateUpdate, ToolData},
|
||||
states::StateHandler,
|
||||
};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
use crate::{comp::StateUpdate, sys::character_state::JoinData};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct State {
|
||||
/// How long before a new action can be performed
|
||||
/// after equipping
|
||||
pub equip_delay: Duration,
|
||||
}
|
||||
|
||||
impl StateHandler for State {
|
||||
fn new(ecs_data: &EcsStateData) -> Self {
|
||||
let equip_delay =
|
||||
if let Some(Tool(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| i.kind) {
|
||||
data.equip_time()
|
||||
} else {
|
||||
Duration::default()
|
||||
};
|
||||
|
||||
Self { equip_delay }
|
||||
}
|
||||
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
energy: *ecs_data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
handle_move_dir(&ecs_data, &mut update);
|
||||
|
||||
if self.equip_delay == Duration::default() {
|
||||
// Wield delay has expired
|
||||
update.character = CharacterState::Wielded(None);
|
||||
} else {
|
||||
// Wield delay hasn't expired yet
|
||||
// Update wield delay
|
||||
update.character = CharacterState::Wielding(Some(State {
|
||||
equip_delay: self
|
||||
.equip_delay
|
||||
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
}));
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
pub fn behavior(ecs_data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
energy: *ecs_data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
handle_move(&ecs_data, &mut update);
|
||||
handle_jump(&ecs_data, &mut update);
|
||||
handle_sit(&ecs_data, &mut update);
|
||||
handle_climb(&ecs_data, &mut update);
|
||||
handle_glide(&ecs_data, &mut update);
|
||||
handle_unwield(&ecs_data, &mut update);
|
||||
handle_primary(&ecs_data, &mut update);
|
||||
handle_secondary(&ecs_data, &mut update);
|
||||
handle_dodge(&ecs_data, &mut update);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -1,20 +1,79 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
AbilityPool, Body, CharacterState, Controller, EcsStateData, Energy, Mounting, Ori,
|
||||
PhysicsState, Pos, Stats, Vel,
|
||||
AbilityPool, Body, CharacterState, Controller, ControllerInputs, Energy, Mounting, Ori,
|
||||
PhysicsState, Pos, StateUpdate, Stats, Vel,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
state::DeltaTime,
|
||||
states,
|
||||
sync::{Uid, UidAllocator},
|
||||
};
|
||||
|
||||
use specs::{Entities, Join, LazyUpdate, Read, ReadStorage, System, WriteStorage};
|
||||
use specs::{Entities, Entity, Join, LazyUpdate, Read, ReadStorage, System, WriteStorage};
|
||||
|
||||
/// ## Character State System
|
||||
use std::collections::VecDeque;
|
||||
|
||||
/// Read-Only Data sent from Character Behavior System to bahvior fn's
|
||||
pub struct JoinData<'a> {
|
||||
pub entity: Entity,
|
||||
pub uid: &'a Uid,
|
||||
pub character: &'a CharacterState,
|
||||
pub pos: &'a Pos,
|
||||
pub vel: &'a Vel,
|
||||
pub ori: &'a Ori,
|
||||
pub dt: &'a DeltaTime,
|
||||
pub controller: &'a Controller,
|
||||
pub inputs: &'a ControllerInputs,
|
||||
pub stats: &'a Stats,
|
||||
pub energy: &'a Energy,
|
||||
pub body: &'a Body,
|
||||
pub physics: &'a PhysicsState,
|
||||
pub ability_pool: &'a AbilityPool,
|
||||
pub updater: &'a LazyUpdate,
|
||||
}
|
||||
|
||||
pub type JoinTuple<'a> = (
|
||||
Entity,
|
||||
&'a Uid,
|
||||
&'a mut CharacterState,
|
||||
&'a mut Pos,
|
||||
&'a mut Vel,
|
||||
&'a mut Ori,
|
||||
&'a mut Energy,
|
||||
&'a Controller,
|
||||
&'a Stats,
|
||||
&'a Body,
|
||||
&'a PhysicsState,
|
||||
&'a AbilityPool,
|
||||
);
|
||||
|
||||
impl<'a> JoinData<'a> {
|
||||
fn new(j: &'a JoinTuple<'a>, updater: &'a LazyUpdate, dt: &'a DeltaTime) -> Self {
|
||||
Self {
|
||||
entity: j.0,
|
||||
uid: j.1,
|
||||
character: j.2,
|
||||
pos: j.3,
|
||||
vel: j.4,
|
||||
ori: j.5,
|
||||
energy: j.6,
|
||||
controller: j.7,
|
||||
inputs: &j.7.inputs,
|
||||
stats: j.8,
|
||||
body: j.9,
|
||||
physics: j.10,
|
||||
ability_pool: j.11,
|
||||
updater,
|
||||
dt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// /// ## Character State System
|
||||
/// #### Calls updates to `CharacterState`s. Acts on tuples of (
|
||||
/// `CharacterState`, `Pos`, `Vel`, and `Ori` ).
|
||||
///
|
||||
/// _System forms `EcsStateData` tuples and passes those to `ActionState`
|
||||
/// _System forms `CharacterEntityData` tuples and passes those to `ActionState`
|
||||
/// `update()` fn, then does the same for `MoveState` `update`_
|
||||
pub struct Sys;
|
||||
|
||||
@ -63,20 +122,7 @@ impl<'a> System<'a> for Sys {
|
||||
mountings,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
for (
|
||||
entity,
|
||||
uid,
|
||||
character,
|
||||
pos,
|
||||
vel,
|
||||
ori,
|
||||
energy,
|
||||
controller,
|
||||
stats,
|
||||
body,
|
||||
physics,
|
||||
ability_pool,
|
||||
) in (
|
||||
let mut join_iter = (
|
||||
&entities,
|
||||
&uids,
|
||||
&mut character_states,
|
||||
@ -90,50 +136,56 @@ impl<'a> System<'a> for Sys {
|
||||
&physics_states,
|
||||
&ability_pools,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let inputs = &controller.inputs;
|
||||
.join();
|
||||
|
||||
while let Some(tuple) = join_iter.next() {
|
||||
let j = JoinData::new(&tuple, &updater, &dt);
|
||||
let inputs = &j.inputs;
|
||||
|
||||
// Being dead overrides all other states
|
||||
if stats.is_dead {
|
||||
if j.stats.is_dead {
|
||||
// Only options: click respawn
|
||||
// prevent instant-respawns (i.e. player was holding attack)
|
||||
// by disallowing while input is held down
|
||||
if inputs.respawn.is_pressed() && !inputs.respawn.is_held_down() {
|
||||
server_bus.emitter().emit(ServerEvent::Respawn(entity));
|
||||
server_bus.emitter().emit(ServerEvent::Respawn(j.entity));
|
||||
}
|
||||
// Or do nothing
|
||||
return;
|
||||
}
|
||||
// If mounted, character state is controlled by mount
|
||||
// TODO: Make mounting a state
|
||||
if let Some(Mounting(_)) = mountings.get(entity) {
|
||||
*character = CharacterState::Sit(None);
|
||||
if let Some(Mounting(_)) = mountings.get(j.entity) {
|
||||
*tuple.2 = CharacterState::Sit {};
|
||||
return;
|
||||
}
|
||||
|
||||
let mut state_update = character.update(&EcsStateData {
|
||||
entity: &entity,
|
||||
uid,
|
||||
character,
|
||||
pos,
|
||||
vel,
|
||||
ori,
|
||||
energy,
|
||||
dt: &dt,
|
||||
inputs,
|
||||
stats,
|
||||
body,
|
||||
physics,
|
||||
updater: &updater,
|
||||
ability_pool,
|
||||
});
|
||||
let mut state_update = match j.character {
|
||||
CharacterState::Idle { .. } => states::idle::behavior(&j),
|
||||
CharacterState::Climb { .. } => states::climb::behavior(&j),
|
||||
CharacterState::Glide { .. } => states::glide::behavior(&j),
|
||||
CharacterState::Roll { .. } => states::roll::behavior(&j),
|
||||
CharacterState::Wielding { .. } => states::wielding::behavior(&j),
|
||||
CharacterState::Equipping { .. } => states::equipping::behavior(&j),
|
||||
CharacterState::BasicAttack { .. } => states::basic_attack::behavior(&j),
|
||||
CharacterState::Sit { .. } => states::sit::behavior(&j),
|
||||
|
||||
*character = state_update.character;
|
||||
*pos = state_update.pos;
|
||||
*vel = state_update.vel;
|
||||
*ori = state_update.ori;
|
||||
*energy = state_update.energy;
|
||||
_ => StateUpdate {
|
||||
character: *j.character,
|
||||
pos: *j.pos,
|
||||
vel: *j.vel,
|
||||
ori: *j.ori,
|
||||
energy: *j.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
},
|
||||
};
|
||||
|
||||
*tuple.2 = state_update.character;
|
||||
*tuple.3 = state_update.pos;
|
||||
*tuple.4 = state_update.vel;
|
||||
*tuple.5 = state_update.ori;
|
||||
*tuple.6 = state_update.energy;
|
||||
local_bus.emitter().append(&mut state_update.local_events);
|
||||
server_bus.emitter().append(&mut state_update.server_events);
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// Accelerate recharging energy if not wielding.
|
||||
match character_state {
|
||||
CharacterState::Idle(_) => {
|
||||
CharacterState::Idle { .. } => {
|
||||
if {
|
||||
let energy = energy.get_unchecked();
|
||||
energy.current() < energy.maximum()
|
||||
@ -92,7 +92,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
},
|
||||
// Wield does not regen and sets the rate back to zero.
|
||||
CharacterState::Wielded(_) => {
|
||||
CharacterState::Wielding { .. } => {
|
||||
if energy.get_unchecked().regen_rate != 0.0 {
|
||||
energy.get_mut_unchecked().regen_rate = 0.0
|
||||
}
|
||||
|
@ -202,10 +202,10 @@ impl MovementEventMapper {
|
||||
|
||||
// Match all other Movemement and Action states
|
||||
match (previous_state.event, character_state) {
|
||||
(_, CharacterState::Roll(_)) => SfxEvent::Roll,
|
||||
(_, CharacterState::Climb(_)) => SfxEvent::Climb,
|
||||
(SfxEvent::Glide, CharacterState::Idle(_)) => SfxEvent::GliderClose,
|
||||
(previous_event, CharacterState::Glide(_)) => {
|
||||
(_, CharacterState::Roll { .. }) => SfxEvent::Roll,
|
||||
(_, CharacterState::Climb { .. }) => SfxEvent::Climb,
|
||||
(SfxEvent::Glide, CharacterState::Idle { .. }) => SfxEvent::GliderClose,
|
||||
(previous_event, CharacterState::Glide { .. }) => {
|
||||
if previous_event != SfxEvent::GliderOpen && previous_event != SfxEvent::Glide {
|
||||
SfxEvent::GliderOpen
|
||||
} else {
|
||||
@ -226,13 +226,13 @@ impl MovementEventMapper {
|
||||
}
|
||||
|
||||
/// This helps us determine whether we should be emitting the Wield/Unwield
|
||||
/// events. For now, consider either CharacterState::Wielded or
|
||||
/// ::Wielding to mean the weapon is drawn. This will need updating if the
|
||||
/// events. For now, consider either CharacterState::Wielding or
|
||||
/// ::Equipping to mean the weapon is drawn. This will need updating if the
|
||||
/// animations change to match the wield_duration associated with the weapon
|
||||
fn weapon_drawn(character: &CharacterState) -> bool {
|
||||
character.is_wielded()
|
||||
|| match character {
|
||||
CharacterState::Wielding(_) => true,
|
||||
CharacterState::Equipping { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ fn maps_idle() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(None),
|
||||
&CharacterState::Idle {},
|
||||
&PhysicsState {
|
||||
on_ground: true,
|
||||
on_wall: None,
|
||||
@ -120,7 +120,7 @@ fn maps_run_with_sufficient_velocity() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(None),
|
||||
&CharacterState::Idle {},
|
||||
&PhysicsState {
|
||||
on_ground: true,
|
||||
on_wall: None,
|
||||
@ -149,7 +149,7 @@ fn does_not_map_run_with_insufficient_velocity() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(None),
|
||||
&CharacterState::Idle {},
|
||||
&PhysicsState {
|
||||
on_ground: true,
|
||||
on_wall: None,
|
||||
@ -178,7 +178,7 @@ fn does_not_map_run_with_sufficient_velocity_but_not_on_ground() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(None),
|
||||
&CharacterState::Idle {},
|
||||
&PhysicsState {
|
||||
on_ground: false,
|
||||
on_wall: None,
|
||||
@ -207,7 +207,7 @@ fn maps_roll() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Roll(None),
|
||||
&CharacterState::Roll {},
|
||||
&PhysicsState {
|
||||
on_ground: true,
|
||||
on_wall: None,
|
||||
@ -236,7 +236,7 @@ fn maps_land_on_ground_to_run() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(None),
|
||||
&CharacterState::Idle {},
|
||||
&PhysicsState {
|
||||
on_ground: true,
|
||||
on_wall: None,
|
||||
@ -265,7 +265,7 @@ fn maps_glider_open() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Glide(None),
|
||||
&CharacterState::Glide {},
|
||||
&PhysicsState {
|
||||
on_ground: false,
|
||||
on_wall: None,
|
||||
@ -294,7 +294,7 @@ fn maps_glide() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Glide(None),
|
||||
&CharacterState::Glide {},
|
||||
&PhysicsState {
|
||||
on_ground: false,
|
||||
on_wall: None,
|
||||
@ -323,7 +323,7 @@ fn maps_glider_close_when_closing_mid_flight() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(None),
|
||||
&CharacterState::Idle {},
|
||||
&PhysicsState {
|
||||
on_ground: false,
|
||||
on_wall: None,
|
||||
@ -352,7 +352,7 @@ fn maps_glider_close_when_landing() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(None),
|
||||
&CharacterState::Idle {},
|
||||
&PhysicsState {
|
||||
on_ground: true,
|
||||
on_wall: None,
|
||||
@ -383,7 +383,7 @@ fn maps_wield() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Wielding(None),
|
||||
&CharacterState::Equipping {},
|
||||
&PhysicsState {
|
||||
on_ground: true,
|
||||
on_wall: None,
|
||||
@ -443,7 +443,7 @@ fn does_not_map_wield_when_no_main_weapon() {
|
||||
);
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Wielded(None),
|
||||
&CharacterState::Wielding {},
|
||||
&PhysicsState {
|
||||
on_ground: true,
|
||||
on_wall: None,
|
||||
|
@ -170,10 +170,10 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
||||
if camera_mode != CameraMode::FirstPerson
|
||||
|| character_state
|
||||
.map(|cs| match cs {
|
||||
CharacterState::BasicAttack(_)
|
||||
| CharacterState::BasicBlock(_)
|
||||
| CharacterState::Wielding(_)
|
||||
| CharacterState::Wielded(_) => true,
|
||||
CharacterState::BasicAttack { .. }
|
||||
| CharacterState::BasicBlock { .. }
|
||||
| CharacterState::Equipping { .. }
|
||||
| CharacterState::Wielding { .. } => true,
|
||||
_ => false,
|
||||
})
|
||||
.unwrap_or_default()
|
||||
|
@ -441,14 +441,16 @@ impl FigureMgr {
|
||||
),
|
||||
};
|
||||
let target_bones = match &character {
|
||||
CharacterState::Roll(_) => anim::character::RollAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, ori.0, state.last_ori, time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
CharacterState::BasicAttack(_) => {
|
||||
CharacterState::Roll { .. } => {
|
||||
anim::character::RollAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, ori.0, state.last_ori, time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::BasicAttack { .. } => {
|
||||
anim::character::AttackAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, time),
|
||||
@ -457,7 +459,7 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::BasicBlock(_) => {
|
||||
CharacterState::BasicBlock { .. } => {
|
||||
anim::character::BlockIdleAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(active_tool_kind, time),
|
||||
@ -476,7 +478,7 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
}*/
|
||||
CharacterState::Wielding(_) => {
|
||||
CharacterState::Equipping { .. } => {
|
||||
anim::character::WieldAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, vel.0.magnitude(), time),
|
||||
@ -485,7 +487,7 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Wielded(_) => {
|
||||
CharacterState::Wielding { .. } => {
|
||||
anim::character::WieldAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, vel.0.magnitude(), time),
|
||||
@ -494,7 +496,7 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Glide(_) => {
|
||||
CharacterState::Glide { .. } => {
|
||||
anim::character::GlidingAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, vel.0, ori.0, state.last_ori, time),
|
||||
@ -503,7 +505,7 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Climb(_) => {
|
||||
CharacterState::Climb { .. } => {
|
||||
anim::character::ClimbAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(active_tool_kind, vel.0, ori.0, time),
|
||||
@ -512,13 +514,15 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Sit(_) => anim::character::SitAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(active_tool_kind, time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
CharacterState::Sit { .. } => {
|
||||
anim::character::SitAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(active_tool_kind, time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
_ => target_base,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user