refactor states to handle update logic

This commit is contained in:
AdamWhitehurst
2019-12-26 06:43:59 -08:00
parent c2ceabea0e
commit 8e0317e03d
29 changed files with 1525 additions and 1393 deletions

View File

@ -1,109 +1,121 @@
use crate::comp::{Body, Controller, ControllerInputs, ItemKind, PhysicsState, Stats}; use self::ActionState::*;
use specs::{Component, FlaggedStorage, HashMapStorage}; use super::states::*;
use specs::{Entities, Join, LazyUpdate, Read, ReadStorage, System}; use crate::{
use sphynx::{Uid, UidAllocator}; comp::{Body, ControllerInputs, Ori, PhysicsState, Pos, Stats, Vel},
//use specs_idvs::IDVStorage; event::{EventBus, LocalEvent, ServerEvent},
use self::{ActionState::*, MovementState::*}; state::DeltaTime,
};
use specs::LazyUpdate;
use specs::{Component, Entity, FlaggedStorage, HashMapStorage, NullStorage};
use sphynx::Uid;
use std::time::Duration; use std::time::Duration;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] pub struct ECSStateData<'a> {
pub struct RunData; pub entity: &'a Entity,
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] pub uid: &'a Uid,
pub struct StandData; pub character: &'a CharacterState,
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] pub pos: &'a Pos,
pub struct SitData; pub vel: &'a Vel,
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] pub ori: &'a Ori,
pub struct JumpData; pub dt: &'a DeltaTime,
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] pub inputs: &'a ControllerInputs,
pub struct FallData; pub stats: &'a Stats,
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] pub body: &'a Body,
pub struct GlideData; pub physics: &'a PhysicsState,
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] pub updater: &'a LazyUpdate,
pub struct SwimData; pub server_bus: &'a EventBus<ServerEvent>,
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] pub local_bus: &'a EventBus<LocalEvent>,
pub struct ClimbData; }
pub struct ECSStateUpdate {
pub character: CharacterState,
pub pos: Pos,
pub vel: Vel,
pub ori: Ori,
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum MovementState { pub enum MoveState {
Stand(StandData), Stand(StandHandler),
Run(RunData), Run(RunHandler),
Sit(SitData), Sit(SitHandler),
Jump(JumpData), Jump(JumpHandler),
Fall(FallData), Fall(FallHandler),
Glide(GlideData), Glide(GlideHandler),
Swim(SwimData), Swim(SwimHandler),
Climb(ClimbData), Climb(ClimbHandler),
} }
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum ActionState { pub enum ActionState {
Idle, Idle,
Wield { Wield(WieldHandler),
time_left: Duration, Attack(AttackKind),
}, Block(BlockKind),
Attack { Dodge(DodgeKind),
time_left: Duration, // Interact,
applied: bool, }
},
Block { #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
time_active: Duration, pub enum AttackKind {
}, BasicAttack(BasicAttackHandler),
Roll { Charge(ChargeAttackHandler),
time_left: Duration, }
// Whether character was wielding before they started roll
was_wielding: bool, #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
}, pub enum BlockKind {
Charge { BasicBlock(BasicBlockHandler),
time_left: Duration, }
},
// Handle(CharacterAction), #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum DodgeKind {
Roll(RollHandler),
} }
impl ActionState { impl ActionState {
pub fn is_wield(&self) -> bool { pub fn is_equip_finished(&self) -> bool {
if let Self::Wield { .. } = self {
true
} else {
false
}
}
pub fn is_action_finished(&self) -> bool {
match self { match self {
Self::Wield { time_left } Wield(WieldHandler { equip_delay }) => *equip_delay == Duration::default(),
| Self::Attack { time_left, .. } _ => true,
| Self::Roll { time_left, .. } }
| Self::Charge { time_left } => *time_left == Duration::default(), }
Self::Idle | Self::Block { .. } => false, pub fn get_delay(&self) -> Duration {
match self {
Wield(WieldHandler { equip_delay }) => *equip_delay,
_ => Duration::default(),
} }
} }
pub fn is_attack(&self) -> bool { pub fn is_attacking(&self) -> bool {
if let Self::Attack { .. } = self { match self {
Block(_) => true,
_ => false,
}
}
pub fn is_blocking(&self) -> bool {
match self {
Attack(_) => true,
_ => false,
}
}
pub fn is_dodging(&self) -> bool {
match self {
Dodge(_) => true,
_ => false,
}
}
pub fn is_wielding(&self) -> bool {
if let Wield(_) = self {
true true
} else { } else {
false false
} }
} }
pub fn is_idling(&self) -> bool {
pub fn is_block(&self) -> bool { if let Idle = self {
if let Self::Block { .. } = self {
true
} else {
false
}
}
pub fn is_roll(&self) -> bool {
if let Self::Roll { .. } = self {
true
} else {
false
}
}
pub fn is_charge(&self) -> bool {
if let Self::Charge { .. } = self {
true true
} else { } else {
false false
@ -113,29 +125,29 @@ impl ActionState {
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct CharacterState { pub struct CharacterState {
pub movement: MovementState, pub move_state: MoveState,
pub action: ActionState, pub action_state: ActionState,
} }
impl CharacterState { impl CharacterState {
pub fn is_same_movement(&self, other: &Self) -> bool { pub fn is_same_move_state(&self, other: &Self) -> bool {
// Check if enum item is the same without looking at the inner data // Check if state is the same without looking at the inner data
std::mem::discriminant(&self.movement) == std::mem::discriminant(&other.movement) std::mem::discriminant(&self.move_state) == std::mem::discriminant(&other.move_state)
} }
pub fn is_same_action(&self, other: &Self) -> bool { pub fn is_same_action_state(&self, other: &Self) -> bool {
// Check if enum item is the same without looking at the inner data // Check if state is the same without looking at the inner data
std::mem::discriminant(&self.action) == std::mem::discriminant(&other.action) std::mem::discriminant(&self.action_state) == std::mem::discriminant(&other.action_state)
} }
pub fn is_same_state(&self, other: &Self) -> bool { pub fn is_same_state(&self, other: &Self) -> bool {
self.is_same_movement(other) && self.is_same_action(other) self.is_same_move_state(other) && self.is_same_action_state(other)
} }
} }
impl Default for CharacterState { impl Default for CharacterState {
fn default() -> Self { fn default() -> Self {
Self { Self {
movement: MovementState::Fall(FallData), move_state: MoveState::Fall(FallHandler),
action: ActionState::Idle, action_state: ActionState::Idle,
} }
} }
} }
@ -143,3 +155,21 @@ impl Default for CharacterState {
impl Component for CharacterState { impl Component for CharacterState {
type Storage = FlaggedStorage<Self, HashMapStorage<Self>>; type Storage = FlaggedStorage<Self, HashMapStorage<Self>>;
} }
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct OverrideState;
impl Component for OverrideState {
type Storage = FlaggedStorage<Self, NullStorage<Self>>;
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct OverrideAction;
impl Component for OverrideAction {
type Storage = FlaggedStorage<Self, NullStorage<Self>>;
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct OverrideMove;
impl Component for OverrideMove {
type Storage = FlaggedStorage<Self, NullStorage<Self>>;
}

View File

@ -10,6 +10,7 @@ mod location;
mod phys; mod phys;
mod player; mod player;
pub mod projectile; pub mod projectile;
mod states;
mod stats; mod stats;
mod visual; mod visual;
@ -21,8 +22,8 @@ pub use body::{
quadruped_medium, quadruped_small, Body, quadruped_medium, quadruped_small, Body,
}; };
pub use character_state::{ pub use character_state::{
ActionState, CharacterState, ClimbData, FallData, GlideData, JumpData, MovementState, RunData, ActionState, AttackKind, BlockKind, CharacterState, DodgeKind, ECSStateData, ECSStateUpdate,
SitData, StandData, SwimData, MoveState, OverrideAction, OverrideMove, OverrideState,
}; };
pub use controller::{ pub use controller::{
ControlEvent, Controller, ControllerInputs, Input, InputState, InventoryManip, MountState, ControlEvent, Controller, ControllerInputs, Input, InputState, InventoryManip, MountState,
@ -35,5 +36,6 @@ pub use location::Waypoint;
pub use phys::{ForceUpdate, Gravity, Mass, Ori, PhysicsState, Pos, Scale, Sticky, Vel}; pub use phys::{ForceUpdate, Gravity, Mass, Ori, PhysicsState, Pos, Scale, Sticky, Vel};
pub use player::Player; pub use player::Player;
pub use projectile::Projectile; pub use projectile::Projectile;
pub use states::*;
pub use stats::{Equipment, Exp, HealthChange, HealthSource, Level, Stats}; pub use stats::{Equipment, Exp, HealthChange, HealthSource, Level, Stats};
pub use visual::LightEmitter; pub use visual::LightEmitter;

View File

@ -0,0 +1,19 @@
use super::{ECSStateData, ECSStateUpdate, StateHandle};
use std::time::Duration;
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct BasicAttackHandler {
/// How long the state has until exitting
remaining_duration: Duration,
}
impl StateHandle for BasicAttackHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
return ECSStateUpdate {
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
character: *ecs_data.character,
};
}
}

View File

@ -0,0 +1,19 @@
use super::{ECSStateData, ECSStateUpdate, StateHandle};
use std::time::Duration;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct BasicBlockHandler {
/// How long the blocking state has been active
active_duration: Duration,
}
impl StateHandle for BasicBlockHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
return ECSStateUpdate {
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
character: *ecs_data.character,
};
}
}

View File

@ -0,0 +1,86 @@
use super::{
CharacterState, ECSStateData, ECSStateUpdate, MoveState::Run, RunHandler, Stand, StandHandler,
StateHandle, WieldHandler,
};
use crate::comp::{
ActionState::{Attack, Idle, Wield},
AttackKind::Charge,
HealthChange, HealthSource,
ItemKind::Tool,
};
use crate::event::ServerEvent;
use std::time::Duration;
use super::TEMP_EQUIP_DELAY;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct ChargeAttackHandler {
/// How long the state has until exitting
pub remaining_duration: Duration,
}
impl StateHandle for ChargeAttackHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
let mut update = ECSStateUpdate {
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
character: *ecs_data.character,
};
if let Some(uid_b) = ecs_data.physics.touch_entity {
ecs_data.server_bus.emitter().emit(ServerEvent::Damage {
uid: uid_b,
change: HealthChange {
amount: -20,
cause: HealthSource::Attack { by: *ecs_data.uid },
},
});
update.character = CharacterState {
move_state: Stand(StandHandler),
action_state: if let Some(Tool { .. }) =
ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind)
{
Wield(WieldHandler {
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
})
} else {
Idle
},
};
return update;
}
if self.remaining_duration == Duration::default() || update.vel.0.magnitude_squared() < 10.0
{
update.character = CharacterState {
move_state: Stand(StandHandler),
action_state: if let Some(Tool { .. }) =
ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind)
{
Wield(WieldHandler {
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
})
} else {
Idle
},
};
return update;
}
update.character = CharacterState {
move_state: Run(RunHandler),
action_state: Attack(Charge(ChargeAttackHandler {
remaining_duration: self
.remaining_duration
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
.unwrap_or_default(),
})),
};
return update;
}
}

View File

@ -0,0 +1,100 @@
use super::{
ActionState::*, CharacterState, ECSStateData, ECSStateUpdate, FallHandler, JumpHandler,
MoveState::*, StandHandler, StateHandle,
};
use super::{CLIMB_SPEED, HUMANOID_CLIMB_ACCEL, HUMANOID_SPEED};
use crate::sys::phys::GRAVITY;
use vek::vec::{Vec2, Vec3};
use vek::Lerp;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct ClimbHandler;
impl StateHandle for ClimbHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
let mut update = ECSStateUpdate {
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
character: *ecs_data.character,
};
// Move player according to move_dir
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
* ecs_data.inputs.move_dir
* if update.vel.0.magnitude_squared() < HUMANOID_SPEED.powf(2.0) {
HUMANOID_CLIMB_ACCEL
} else {
0.0
};
// Set direction based on move direction when on the ground
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)
}
} 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,
);
}
// 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),
);
}
}
if let None = ecs_data.physics.on_wall {
if ecs_data.inputs.jump.is_pressed() {
update.character = CharacterState {
action_state: Idle,
move_state: Jump(JumpHandler),
};
return update;
} else {
update.character = CharacterState {
action_state: Idle,
move_state: Fall(FallHandler),
};
return update;
}
}
if ecs_data.physics.on_ground {
update.character = CharacterState {
action_state: Idle,
move_state: Stand(StandHandler),
};
return update;
}
return update;
}
}

View File

@ -0,0 +1,89 @@
use super::{
ActionState::*, CharacterState, ECSStateData, ECSStateUpdate, GlideHandler, MoveState::*,
RunHandler, StandHandler, StateHandle, SwimHandler,
};
use super::{HUMANOID_AIR_ACCEL, HUMANOID_AIR_SPEED};
use vek::{Vec2, Vec3};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct FallHandler;
impl StateHandle for FallHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
let mut update = ECSStateUpdate {
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
character: *ecs_data.character,
};
// Move player according to movement direction vector
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
* ecs_data.inputs.move_dir
* if update.vel.0.magnitude_squared() < HUMANOID_AIR_SPEED.powf(2.0) {
HUMANOID_AIR_ACCEL
} else {
0.0
};
// Set orientation vector based on direction of movement when on the ground
let ori_dir = if update.character.action_state.is_attacking()
|| update.character.action_state.is_blocking()
{
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(), 2.0 * ecs_data.dt.0);
}
// Check gliding
if ecs_data.inputs.glide.is_pressed() && !ecs_data.inputs.glide.is_held_down() {
update.character = CharacterState {
action_state: Idle,
move_state: Glide(GlideHandler),
};
return update;
}
// Not on ground, go to swim or fall
if !ecs_data.physics.on_ground {
// Check if in fluid to go to swimming or back to falling
if ecs_data.physics.in_fluid {
update.character = CharacterState {
action_state: update.character.action_state,
move_state: Swim(SwimHandler),
};
return update;
} else {
update.character = CharacterState {
action_state: update.character.action_state,
move_state: Fall(FallHandler),
};
return update;
}
}
// On ground
else {
// Return to running or standing based on move inputs
update.character = CharacterState {
action_state: update.character.action_state,
move_state: if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
Run(RunHandler)
} else {
Stand(StandHandler)
},
};
return update;
}
}
}

View File

@ -0,0 +1,87 @@
use super::{
ActionState::*, CharacterState, ClimbHandler, ECSStateData, ECSStateUpdate, FallHandler,
MoveState::*, StandHandler, StateHandle,
};
use super::{GLIDE_ACCEL, GLIDE_ANTIGRAV, GLIDE_SPEED};
use vek::{Vec2, Vec3};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct GlideHandler;
impl StateHandle for GlideHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
let mut update = ECSStateUpdate {
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
character: *ecs_data.character,
};
// 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 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);
}
// If glide button isn't held
if !ecs_data.inputs.glide.is_pressed() {
update.character = CharacterState {
action_state: Idle,
move_state: Fall(FallHandler),
};
return update;
}
// If there is a wall in front of character go to climb
else if let Some(_wall_dir) = ecs_data.physics.on_wall {
update.character = CharacterState {
action_state: Idle,
move_state: Climb(ClimbHandler),
};
return update;
}
// If on ground go to stand
if ecs_data.physics.on_ground {
update.character = CharacterState {
action_state: Idle,
move_state: Stand(StandHandler),
};
return update;
}
// Otherwise keep gliding
update.character = CharacterState {
action_state: Idle,
move_state: Glide(GlideHandler),
};
return update;
}
}

View File

@ -0,0 +1,28 @@
use super::{CharacterState, ECSStateData, ECSStateUpdate, FallHandler, MoveState::*, StateHandle};
use crate::event::LocalEvent;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct JumpHandler;
impl StateHandle for JumpHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
let mut update = ECSStateUpdate {
character: *ecs_data.character,
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
};
ecs_data
.local_bus
.emitter()
.emit(LocalEvent::Jump(*ecs_data.entity));
update.character = CharacterState {
action_state: ecs_data.character.action_state,
move_state: Fall(FallHandler),
};
return update;
}
}

View File

@ -0,0 +1,104 @@
// Module declarations
mod basic_attack;
mod basic_block;
mod charge_attack;
mod climb;
mod fall;
mod glide;
mod jump;
mod roll;
mod run;
mod sit;
mod stand;
mod swim;
mod wield;
// Reexports
pub use basic_attack::*;
pub use basic_block::*;
pub use charge_attack::*;
pub use climb::*;
pub use fall::*;
pub use glide::*;
pub use jump::*;
pub use roll::*;
pub use run::*;
pub use sit::*;
pub use stand::*;
pub use swim::*;
pub use wield::*;
// TODO: Attach these to racial components and/or ecs resources
pub const HUMANOID_ACCEL: f32 = 50.0;
pub const HUMANOID_SPEED: f32 = 120.0;
pub const HUMANOID_AIR_ACCEL: f32 = 10.0;
pub const HUMANOID_AIR_SPEED: f32 = 100.0;
pub const HUMANOID_WATER_ACCEL: f32 = 70.0;
pub const HUMANOID_WATER_SPEED: f32 = 120.0;
pub const HUMANOID_CLIMB_ACCEL: f32 = 5.0;
pub const ROLL_SPEED: f32 = 17.0;
pub const CHARGE_SPEED: f32 = 20.0;
pub const GLIDE_ACCEL: f32 = 15.0;
pub const GLIDE_SPEED: f32 = 45.0;
pub const BLOCK_ACCEL: f32 = 30.0;
pub const BLOCK_SPEED: f32 = 75.0;
pub const TEMP_EQUIP_DELAY: u64 = 100;
// Gravity is 9.81 * 4, so this makes gravity equal to .15
pub const GLIDE_ANTIGRAV: f32 = crate::sys::phys::GRAVITY * 0.96;
pub const CLIMB_SPEED: f32 = 5.0;
pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
// Public interface, wires character states to their handlers.
use super::{
ActionState, ActionState::*, AttackKind::*, BlockKind::*, CharacterState, DodgeKind::*,
ECSStateData, ECSStateUpdate, MoveState, MoveState::*,
};
pub trait StateHandle {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate;
}
impl StateHandle for ActionState {
/// Passes handle to variant or subvariant handlers
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
match self {
Attack(kind) => match kind {
BasicAttack(handler) => handler.handle(ecs_data),
Charge(handler) => handler.handle(ecs_data),
},
Block(kind) => match kind {
BasicBlock(handler) => handler.handle(ecs_data),
},
Dodge(kind) => match kind {
Roll(handler) => handler.handle(ecs_data),
},
Wield(handler) => handler.handle(ecs_data),
Idle => ECSStateUpdate {
character: *ecs_data.character,
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
},
// All states should be explicitly handled
// Do not use default match: _ => {},
}
}
}
impl StateHandle for MoveState {
/// Passes handle to variant handlers
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
match self {
Stand(handler) => handler.handle(&ecs_data),
Run(handler) => handler.handle(&ecs_data),
Jump(handler) => handler.handle(&ecs_data),
Climb(handler) => handler.handle(&ecs_data),
Glide(handler) => handler.handle(&ecs_data),
Swim(handler) => handler.handle(&ecs_data),
Fall(handler) => handler.handle(&ecs_data),
Sit(handler) => handler.handle(&ecs_data),
// All states should be explicitly handled
// Do not use default match: _ => {},
}
}
}

View File

@ -0,0 +1,19 @@
use super::{ECSStateData, ECSStateUpdate, StateHandle};
use std::time::Duration;
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct RollHandler {
/// How long the state has until exitting
remaining_duration: Duration,
}
impl StateHandle for RollHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
ECSStateUpdate {
character: *ecs_data.character,
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
}
}
}

View File

@ -0,0 +1,139 @@
use super::{
ActionState::*, CharacterState, ClimbHandler, ECSStateData, ECSStateUpdate, FallHandler,
GlideHandler, JumpHandler, MoveState::*, SitHandler, StandHandler, StateHandle, SwimHandler,
};
use super::{HUMANOID_ACCEL, HUMANOID_SPEED};
use vek::vec::{Vec2, Vec3};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct RunHandler;
impl StateHandle for RunHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
let mut update = ECSStateUpdate {
character: *ecs_data.character,
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
};
// Move player according to move_dir
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
* ecs_data.inputs.move_dir
* if update.vel.0.magnitude_squared() < HUMANOID_SPEED.powf(2.0) {
HUMANOID_ACCEL
} else {
0.0
};
// Set direction based on move direction when on the ground
let ori_dir = if update.character.action_state.is_attacking()
|| update.character.action_state.is_blocking()
{
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(), 9.0 * ecs_data.dt.0);
}
// Try to sit
if ecs_data.inputs.sit.is_pressed()
&& ecs_data.physics.on_ground
&& ecs_data.body.is_humanoid()
{
update.character = CharacterState {
action_state: Idle,
move_state: Sit(SitHandler),
};
return update;
}
// Try to climb
if let (true, Some(_wall_dir)) = (
ecs_data.inputs.climb.is_pressed() | ecs_data.inputs.climb_down.is_pressed()
&& ecs_data.body.is_humanoid(),
ecs_data.physics.on_wall,
) {
update.character = CharacterState {
action_state: Idle,
move_state: Climb(ClimbHandler),
};
return update;
}
// Try to swim
if !ecs_data.physics.on_ground && ecs_data.physics.in_fluid {
update.character = CharacterState {
action_state: ecs_data.character.action_state,
move_state: Swim(SwimHandler),
};
return update;
}
// While on ground ...
if ecs_data.physics.on_ground {
// Try to jump
if ecs_data.inputs.jump.is_pressed() && !ecs_data.inputs.jump.is_held_down() {
update.character = CharacterState {
action_state: ecs_data.character.action_state,
move_state: Jump(JumpHandler),
};
return update;
}
// Try to dodge
if ecs_data.inputs.roll.is_pressed() && ecs_data.body.is_humanoid() {
// updater.insert(entity, DodgeStart);
}
}
// While not on ground ...
else {
// Try to glide
if ecs_data.physics.on_wall == None
&& ecs_data.inputs.glide.is_pressed()
&& !ecs_data.inputs.glide.is_held_down()
&& ecs_data.body.is_humanoid()
{
update.character = CharacterState {
action_state: Idle,
move_state: Glide(GlideHandler),
};
return update;
}
update.character = CharacterState {
action_state: ecs_data.character.action_state,
move_state: Fall(FallHandler),
};
return update;
}
if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
update.character = CharacterState {
action_state: ecs_data.character.action_state,
move_state: Run(RunHandler),
};
return update;
} else {
update.character = CharacterState {
action_state: ecs_data.character.action_state,
move_state: Stand(StandHandler),
};
return update;
}
}
}

View File

@ -0,0 +1,76 @@
use super::{
ActionState::*, CharacterState, ECSStateData, ECSStateUpdate, FallHandler, JumpHandler,
MoveState::*, RunHandler, StandHandler, StateHandle, SwimHandler,
};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct SitHandler;
impl StateHandle for SitHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
let mut update = ECSStateUpdate {
character: *ecs_data.character,
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
};
// Falling
// Idk, maybe the ground disappears,
// suddenly maybe a water spell appears.
// Can't hurt to be safe :shrug:
if !ecs_data.physics.on_ground {
if ecs_data.physics.in_fluid {
update.character = CharacterState {
action_state: Idle,
move_state: Swim(SwimHandler),
};
return update;
} else {
update.character = CharacterState {
action_state: Idle,
move_state: Fall(FallHandler),
};
return update;
}
}
// Jumping
if ecs_data.inputs.jump.is_pressed() {
update.character = CharacterState {
action_state: Idle,
move_state: Jump(JumpHandler),
};
return update;
}
// Moving
if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
update.character = CharacterState {
action_state: Idle,
move_state: Run(RunHandler),
};
return update;
}
// Standing back up (unsitting)
if ecs_data.inputs.sit.is_just_pressed() {
update.character = CharacterState {
action_state: Idle,
move_state: Stand(StandHandler),
};
return update;
}
// no move_state has occurred
update.character = CharacterState {
action_state: Idle,
move_state: Sit(SitHandler),
};
return update;
}
}

View File

@ -0,0 +1,120 @@
use super::{
ActionState::*, CharacterState, ClimbHandler, ECSStateData, ECSStateUpdate, FallHandler,
GlideHandler, JumpHandler, MoveState::*, RunHandler, SitHandler, StateHandle, SwimHandler,
};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct StandHandler;
impl StateHandle for StandHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
let mut update = ECSStateUpdate {
character: *ecs_data.character,
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
};
// Try to sit
if ecs_data.inputs.sit.is_pressed()
&& ecs_data.physics.on_ground
&& ecs_data.body.is_humanoid()
{
update.character = CharacterState {
move_state: Sit(SitHandler),
action_state: update.character.action_state,
};
return update;
}
// Try to climb
if let (true, Some(_wall_dir)) = (
ecs_data.inputs.climb.is_pressed() | ecs_data.inputs.climb_down.is_pressed()
&& ecs_data.body.is_humanoid(),
ecs_data.physics.on_wall,
) {
update.character = CharacterState {
action_state: update.character.action_state,
move_state: Climb(ClimbHandler),
};
return update;
}
// Try to swim
if !ecs_data.physics.on_ground && ecs_data.physics.in_fluid {
update.character = CharacterState {
action_state: update.character.action_state,
move_state: Swim(SwimHandler),
};
return update;
}
// While on ground ...
if ecs_data.physics.on_ground {
// Try to jump
if ecs_data.inputs.jump.is_pressed() {
update.character = CharacterState {
action_state: update.character.action_state,
move_state: Jump(JumpHandler),
};
return update;
}
// // Try to charge
// if inputs.charge.is_pressed() && !inputs.charge.is_held_down() {
// }
// Try to roll
if ecs_data.inputs.roll.is_pressed() && ecs_data.body.is_humanoid() {
// updater.insert(entity, DodgeStart);
}
}
// While not on ground ...
else {
// Try to glide
if ecs_data.physics.on_wall == None
&& ecs_data.inputs.glide.is_pressed()
&& !ecs_data.inputs.glide.is_held_down()
&& ecs_data.body.is_humanoid()
{
update.character = CharacterState {
action_state: Idle,
move_state: Glide(GlideHandler),
};
return update;
}
update.character = CharacterState {
action_state: update.character.action_state,
move_state: Fall(FallHandler),
};
return update;
}
if ecs_data.inputs.primary.is_pressed() {
// updater.insert(entity, PrimaryStart);
} else if ecs_data.inputs.secondary.is_pressed() {
// updater.insert(entity, SecondaryStart);
}
if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
update.character = CharacterState {
action_state: update.character.action_state,
move_state: Run(RunHandler),
};
return update;
} else {
update.character = CharacterState {
action_state: update.character.action_state,
move_state: Stand(StandHandler),
};
return update;
}
}
}

View File

@ -0,0 +1,85 @@
use super::{
CharacterState, ECSStateData, ECSStateUpdate, MoveState::*, RunHandler, StandHandler,
StateHandle,
};
use super::{HUMANOID_WATER_ACCEL, HUMANOID_WATER_SPEED};
use crate::sys::phys::GRAVITY;
use vek::{Vec2, Vec3};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct SwimHandler;
impl StateHandle for SwimHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
let mut update = ECSStateUpdate {
character: *ecs_data.character,
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
};
// 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.action_state.is_attacking()
|| update.character.action_state.is_blocking()
{
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,
);
}
if ecs_data.inputs.jump.is_pressed() {
update.vel.0.z =
(update.vel.0.z + ecs_data.dt.0 * GRAVITY * 1.25).min(HUMANOID_WATER_SPEED);
}
if ecs_data.inputs.primary.is_pressed() {
// TODO: PrimaryStart
} else if ecs_data.inputs.secondary.is_pressed() {
// TODO: SecondaryStart
}
// Not on ground
if !ecs_data.physics.on_ground {
update.character = CharacterState {
action_state: ecs_data.character.action_state,
move_state: Swim(SwimHandler),
};
return update;
}
// On ground
else {
// Return to running or standing based on move inputs
update.character = CharacterState {
action_state: ecs_data.character.action_state,
move_state: if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
Run(RunHandler)
} else {
Stand(StandHandler)
},
};
return update;
}
}
}

View File

@ -0,0 +1,51 @@
use super::{ActionState::*, CharacterState, ECSStateData, ECSStateUpdate, StateHandle};
use std::time::Duration;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct WieldHandler {
/// How long before a new action can be performed
/// after equipping
pub equip_delay: Duration,
}
impl StateHandle for WieldHandler {
fn handle(&self, ecs_data: &ECSStateData) -> ECSStateUpdate {
let mut update = ECSStateUpdate {
character: *ecs_data.character,
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
};
// Toggling Weapons
if ecs_data.inputs.toggle_wield.is_pressed()
&& ecs_data.character.action_state.is_equip_finished()
{
update.character = CharacterState {
action_state: Idle,
move_state: ecs_data.character.move_state,
};
return update;
}
if ecs_data.inputs.primary.is_pressed() {
// TODO: PrimaryStart
} else if ecs_data.inputs.secondary.is_pressed() {
// TODO: SecondaryStart
}
// Update wield delay
update.character = CharacterState {
action_state: Wield(WieldHandler {
equip_delay: self
.equip_delay
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
.unwrap_or_default(),
}),
move_state: ecs_data.character.move_state,
};
return update;
}
}

View File

@ -33,6 +33,9 @@ sphynx::sum_type! {
Projectile(comp::Projectile), Projectile(comp::Projectile),
Gravity(comp::Gravity), Gravity(comp::Gravity),
Sticky(comp::Sticky), Sticky(comp::Sticky),
OverrideAction(comp::OverrideAction),
OverrideMove(comp::OverrideMove),
OverrideState(comp::OverrideState),
} }
} }
// Automatically derive From<T> for EcsCompPhantom // Automatically derive From<T> for EcsCompPhantom
@ -56,6 +59,9 @@ sphynx::sum_type! {
Projectile(PhantomData<comp::Projectile>), Projectile(PhantomData<comp::Projectile>),
Gravity(PhantomData<comp::Gravity>), Gravity(PhantomData<comp::Gravity>),
Sticky(PhantomData<comp::Sticky>), Sticky(PhantomData<comp::Sticky>),
OverrideAction(PhantomData<comp::OverrideAction>),
OverrideMove(PhantomData<comp::OverrideMove>),
OverrideState(PhantomData<comp::OverrideState>),
} }
} }
impl sphynx::CompPacket for EcsCompPacket { impl sphynx::CompPacket for EcsCompPacket {

View File

@ -136,6 +136,9 @@ impl State {
ecs.register_synced::<comp::Sticky>(); ecs.register_synced::<comp::Sticky>();
ecs.register_synced::<comp::Gravity>(); ecs.register_synced::<comp::Gravity>();
ecs.register_synced::<comp::Projectile>(); ecs.register_synced::<comp::Projectile>();
ecs.register_synced::<comp::OverrideAction>();
ecs.register_synced::<comp::OverrideMove>();
ecs.register_synced::<comp::OverrideState>();
// Register components send from clients -> server // Register components send from clients -> server
ecs.register::<comp::Controller>(); ecs.register::<comp::Controller>();

View File

@ -1,6 +1,6 @@
use crate::comp::{ use crate::comp::{
Agent, CharacterState, Controller, ControllerInputs, GlideData, MountState, Agent, CharacterState, Controller, ControllerInputs, GlideHandler, MountState,
MovementState::Glide, Pos, Stats, MoveState::Glide, Pos, SitHandler, Stats,
}; };
use crate::pathfinding::WorldPath; use crate::pathfinding::WorldPath;
use crate::terrain::TerrainGrid; use crate::terrain::TerrainGrid;
@ -163,7 +163,7 @@ impl<'a> System<'a> for Sys {
inputs.roll.set_state(true); inputs.roll.set_state(true);
} }
if target_character.movement == Glide(GlideData) if target_character.move_state == Glide(GlideHandler)
&& target_pos.0.z > pos.0.z + 5.0 && target_pos.0.z > pos.0.z + 5.0
{ {
inputs.glide.set_state(true); inputs.glide.set_state(true);

File diff suppressed because it is too large Load Diff

View File

@ -46,119 +46,119 @@ impl<'a> System<'a> for Sys {
stats, stats,
): Self::SystemData, ): Self::SystemData,
) { ) {
let mut server_emitter = server_bus.emitter(); // let mut server_emitter = server_bus.emitter();
let mut _local_emitter = local_bus.emitter(); // let mut _local_emitter = local_bus.emitter();
// Attacks // // Attacks
for (entity, uid, pos, ori, _, stat) in ( // for (entity, uid, pos, ori, _, stat) in (
&entities, // &entities,
&uids, // &uids,
&positions, // &positions,
&orientations, // &orientations,
&controllers, // &controllers,
&stats, // &stats,
) // )
.join() // .join()
{ // {
let recover_duration = if let Some(Item { // let recover_duration = if let Some(Item {
kind: ItemKind::Tool { kind, .. }, // kind: ItemKind::Tool { kind, .. },
.. // ..
}) = stat.equipment.main // }) = stat.equipment.main
{ // {
kind.attack_recover_duration() // kind.attack_recover_duration()
} else { // } else {
Duration::from_secs(1) // Duration::from_secs(1)
}; // };
let (deal_damage, should_end) = if let Some(Attack { time_left, applied }) = // let (deal_damage, should_end) = if let Some(Attack { time_left, applied }) =
&mut character_states.get_mut(entity).map(|c| &mut c.action) // &mut character_states.get_mut(entity).map(|c| &mut c.action)
{ // {
*time_left = time_left // *time_left = time_left
.checked_sub(Duration::from_secs_f32(dt.0)) // .checked_sub(Duration::from_secs_f32(dt.0))
.unwrap_or_default(); // .unwrap_or_default();
if !*applied && recover_duration > *time_left { // if !*applied && recover_duration > *time_left {
*applied = true; // *applied = true;
(true, false) // (true, false)
} else if *time_left == Duration::default() { // } else if *time_left == Duration::default() {
(false, true) // (false, true)
} else { // } else {
(false, false) // (false, false)
} // }
} else { // } else {
(false, false) // (false, false)
}; // };
if deal_damage { // if deal_damage {
if let Some(Attack { .. }) = &character_states.get(entity).map(|c| c.action) { // if let Some(Attack { .. }) = &character_states.get(entity).map(|c| c.action) {
// Go through all other entities // // Go through all other entities
for (b, uid_b, pos_b, ori_b, character_b, stat_b) in ( // for (b, uid_b, pos_b, ori_b, character_b, stat_b) in (
&entities, // &entities,
&uids, // &uids,
&positions, // &positions,
&orientations, // &orientations,
&character_states, // &character_states,
&stats, // &stats,
) // )
.join() // .join()
{ // {
// 2D versions // // 2D versions
let pos2 = Vec2::from(pos.0); // let pos2 = Vec2::from(pos.0);
let pos_b2: Vec2<f32> = Vec2::from(pos_b.0); // let pos_b2: Vec2<f32> = Vec2::from(pos_b.0);
let ori2 = Vec2::from(ori.0); // let ori2 = Vec2::from(ori.0);
// Check if it is a hit // // Check if it is a hit
if entity != b // if entity != b
&& !stat_b.is_dead // && !stat_b.is_dead
&& pos.0.distance_squared(pos_b.0) < ATTACK_RANGE.powi(2) // && pos.0.distance_squared(pos_b.0) < ATTACK_RANGE.powi(2)
// TODO: Use size instead of 1.0 // // TODO: Use size instead of 1.0
&& ori2.angle_between(pos_b2 - pos2) < (2.0 / pos2.distance(pos_b2)).atan() // && ori2.angle_between(pos_b2 - pos2) < (2.0 / pos2.distance(pos_b2)).atan()
{ // {
// Weapon gives base damage // // Weapon gives base damage
let mut dmg = if let Some(ItemKind::Tool { power, .. }) = // let mut dmg = if let Some(ItemKind::Tool { power, .. }) =
stat.equipment.main.as_ref().map(|i| &i.kind) // stat.equipment.main.as_ref().map(|i| &i.kind)
{ // {
*power as i32 // *power as i32
} else { // } else {
1 // 1
}; // };
// Block // // Block
if character_b.action.is_block() // if character_b.action.is_block()
&& ori_b.0.angle_between(pos.0 - pos_b.0).to_degrees() // && ori_b.0.angle_between(pos.0 - pos_b.0).to_degrees()
< BLOCK_ANGLE / 2.0 // < BLOCK_ANGLE / 2.0
{ // {
dmg = (dmg as f32 * (1.0 - BLOCK_EFFICIENCY)) as i32 // dmg = (dmg as f32 * (1.0 - BLOCK_EFFICIENCY)) as i32
} // }
server_emitter.emit(ServerEvent::Damage { // server_emitter.emit(ServerEvent::Damage {
uid: *uid_b, // uid: *uid_b,
change: HealthChange { // change: HealthChange {
amount: -dmg, // amount: -dmg,
cause: HealthSource::Attack { by: *uid }, // cause: HealthSource::Attack { by: *uid },
}, // },
}); // });
} // }
} // }
} // }
} // }
if should_end { // if should_end {
if let Some(character) = &mut character_states.get_mut(entity) { // if let Some(character) = &mut character_states.get_mut(entity) {
character.action = Wield { // character.action = Wield {
time_left: Duration::default(), // time_left: Duration::default(),
}; // };
} // }
} // }
if let Some(Wield { time_left }) = // if let Some(Wield { time_left }) =
&mut character_states.get_mut(entity).map(|c| &mut c.action) // &mut character_states.get_mut(entity).map(|c| &mut c.action)
{ // {
if *time_left != Duration::default() { // if *time_left != Duration::default() {
*time_left = time_left // *time_left = time_left
.checked_sub(Duration::from_secs_f32(dt.0)) // .checked_sub(Duration::from_secs_f32(dt.0))
.unwrap_or_default(); // .unwrap_or_default();
} // }
} // }
} // }
} }
} }

View File

@ -1,20 +1,13 @@
use super::movement::ROLL_DURATION;
use crate::{ use crate::{
comp::{ comp::{ControlEvent, Controller},
self, item, projectile, ActionState, ActionState::*, Body, CharacterState, ControlEvent, event::{EventBus, LocalEvent, ServerEvent},
Controller, ControllerInputs, HealthChange, HealthSource, ItemKind, Mounting,
MovementState, MovementState::*, PhysicsState, Projectile, Stats, Vel,
},
event::{Emitter, EventBus, LocalEvent, ServerEvent},
state::DeltaTime, state::DeltaTime,
}; };
use specs::{ use specs::{
saveload::{Marker, MarkerAllocator}, saveload::{Marker, MarkerAllocator},
Entities, Entity, Join, Read, ReadStorage, System, WriteStorage, Entities, Join, Read, ReadStorage, System, WriteStorage,
}; };
use sphynx::{Uid, UidAllocator}; use sphynx::{Uid, UidAllocator};
use std::time::Duration;
use vek::*;
/// # Controller System /// # Controller System
/// #### Responsible for validating and updating controller inputs /// #### Responsible for validating and updating controller inputs

View File

@ -3,7 +3,6 @@ pub mod character_state;
mod cleanup; mod cleanup;
pub mod combat; pub mod combat;
pub mod controller; pub mod controller;
pub mod movement;
pub mod phys; pub mod phys;
mod projectile; mod projectile;
mod stats; mod stats;
@ -16,7 +15,6 @@ const AGENT_SYS: &str = "agent_sys";
const CHARACTER_STATE_SYS: &str = "character_state_sys"; const CHARACTER_STATE_SYS: &str = "character_state_sys";
const CONTROLLER_SYS: &str = "controller_sys"; const CONTROLLER_SYS: &str = "controller_sys";
const PHYS_SYS: &str = "phys_sys"; const PHYS_SYS: &str = "phys_sys";
const MOVEMENT_SYS: &str = "movement_sys";
const PROJECTILE_SYS: &str = "projectile_sys"; const PROJECTILE_SYS: &str = "projectile_sys";
const COMBAT_SYS: &str = "combat_sys"; const COMBAT_SYS: &str = "combat_sys";
const STATS_SYS: &str = "stats_sys"; const STATS_SYS: &str = "stats_sys";
@ -26,13 +24,12 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); dispatch_builder.add(agent::Sys, AGENT_SYS, &[]);
dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[AGENT_SYS]); dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[AGENT_SYS]);
dispatch_builder.add(character_state::Sys, CHARACTER_STATE_SYS, &[CONTROLLER_SYS]); dispatch_builder.add(character_state::Sys, CHARACTER_STATE_SYS, &[CONTROLLER_SYS]);
dispatch_builder.add(movement::Sys, MOVEMENT_SYS, &[CHARACTER_STATE_SYS]);
dispatch_builder.add(combat::Sys, COMBAT_SYS, &[CONTROLLER_SYS]); dispatch_builder.add(combat::Sys, COMBAT_SYS, &[CONTROLLER_SYS]);
dispatch_builder.add(stats::Sys, STATS_SYS, &[COMBAT_SYS]); dispatch_builder.add(stats::Sys, STATS_SYS, &[COMBAT_SYS]);
dispatch_builder.add( dispatch_builder.add(
phys::Sys, phys::Sys,
PHYS_SYS, PHYS_SYS,
&[CONTROLLER_SYS, MOVEMENT_SYS, COMBAT_SYS, STATS_SYS], &[CONTROLLER_SYS, COMBAT_SYS, STATS_SYS],
); );
dispatch_builder.add(projectile::Sys, PROJECTILE_SYS, &[PHYS_SYS]); dispatch_builder.add(projectile::Sys, PROJECTILE_SYS, &[PHYS_SYS]);
dispatch_builder.add(cleanup::Sys, CLEANUP_SYS, &[PHYS_SYS]); dispatch_builder.add(cleanup::Sys, CLEANUP_SYS, &[PHYS_SYS]);

View File

@ -1,8 +1,8 @@
use super::phys::GRAVITY; use super::phys::GRAVITY;
use crate::{ use crate::{
comp::{ comp::{
CharacterState, Controller, Mounting, MovementState::*, Ori, PhysicsState, Pos, RunData, CharacterState, Controller, Mounting, MoveState::*, Ori, PhysicsState, Pos, RunHandler,
StandData, Stats, Vel, StandHandler, Stats, Vel,
}, },
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
state::DeltaTime, state::DeltaTime,
@ -106,7 +106,7 @@ impl<'a> System<'a> for Sys {
) )
.join() .join()
{ {
// if character.movement == Run(RunData) || character.movement == Stand(StandData) { // if character.movement == Run(RunHandler) || character.movement == Stand(StandHandler) {
// continue; // continue;
// } // }

View File

@ -4,7 +4,11 @@ use crate::audio::sfx::{SfxTriggerItem, SfxTriggers};
use client::Client; use client::Client;
use common::{ use common::{
comp::{ActionState, Body, CharacterState, ItemKind, MovementState, Pos, Stats}, comp::{
ActionState, AttackKind::*, BasicAttackHandler, Body, CharacterState, DodgeKind::*,
FallHandler, GlideHandler, ItemKind, MoveState, Pos, RollHandler, RunHandler, StandHandler,
Stats,
},
event::{EventBus, SfxEvent, SfxEventItem}, event::{EventBus, SfxEvent, SfxEventItem},
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
@ -125,7 +129,7 @@ impl SfxEventMapper {
} }
} }
/// Voxygen has an existing list of character states via `MovementState::*` and `ActionState::*` /// Voxygen has an existing list of character states via `MoveState::*` and `ActionState::*`
/// however that list does not provide enough resolution to target specific entity events, such /// however that list does not provide enough resolution to target specific entity events, such
/// as opening or closing the glider. These methods translate those entity states with some additional /// as opening or closing the glider. These methods translate those entity states with some additional
/// data into more specific `SfxEvent`'s which we attach sounds to /// data into more specific `SfxEvent`'s which we attach sounds to
@ -135,8 +139,8 @@ impl SfxEventMapper {
stats: &Stats, stats: &Stats,
) -> SfxEvent { ) -> SfxEvent {
match ( match (
current_event.movement, current_event.move_state,
current_event.action, current_event.action_state,
previous_event, previous_event,
stats, stats,
) { ) {
@ -154,23 +158,23 @@ impl SfxEventMapper {
stats: &Stats, stats: &Stats,
) -> SfxEvent { ) -> SfxEvent {
match ( match (
current_event.movement, current_event.move_state,
current_event.action, current_event.action_state,
previous_event, previous_event,
stats, stats,
) { ) {
(_, ActionState::Roll { .. }, ..) => SfxEvent::Roll, (_, ActionState::Dodge(_), ..) => SfxEvent::Roll,
(MovementState::Climb(_), ..) => SfxEvent::Climb, (MoveState::Climb(_), ..) => SfxEvent::Climb,
(MovementState::Swim(_), ..) => SfxEvent::Swim, (MoveState::Swim(_), ..) => SfxEvent::Swim,
(MovementState::Run(_), ..) => SfxEvent::Run, (MoveState::Run(_), ..) => SfxEvent::Run,
(MovementState::Fall(_), _, previous_event, _) => { (MoveState::Fall(_), _, previous_event, _) => {
if previous_event != SfxEvent::Glide { if previous_event != SfxEvent::Glide {
SfxEvent::Fall SfxEvent::Fall
} else { } else {
SfxEvent::GliderClose SfxEvent::GliderClose
} }
} }
(MovementState::Glide(_), _, previous_event, ..) => { (MoveState::Glide(_), _, previous_event, ..) => {
if previous_event != SfxEvent::GliderOpen && previous_event != SfxEvent::Glide { if previous_event != SfxEvent::GliderOpen && previous_event != SfxEvent::Glide {
SfxEvent::GliderOpen SfxEvent::GliderOpen
} else { } else {
@ -193,7 +197,7 @@ mod tests {
use super::*; use super::*;
use common::{ use common::{
assets, assets,
comp::{item::Tool, ActionState, MovementState, Stats}, comp::{item::Tool, ActionState, MoveState, Stats},
event::SfxEvent, event::SfxEvent,
}; };
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -273,8 +277,8 @@ mod tests {
let result = SfxEventMapper::map_character_event( let result = SfxEventMapper::map_character_event(
&CharacterState { &CharacterState {
movement: MovementState::Stand, move_state: MoveState::Stand(StandHandler),
action: ActionState::Idle, action_state: ActionState::Idle,
}, },
SfxEvent::Idle, SfxEvent::Idle,
&stats, &stats,
@ -289,8 +293,8 @@ mod tests {
let result = SfxEventMapper::map_character_event( let result = SfxEventMapper::map_character_event(
&CharacterState { &CharacterState {
movement: MovementState::Run, move_state: MoveState::Run(RunHandler),
action: ActionState::Idle, action_state: ActionState::Idle,
}, },
SfxEvent::Idle, SfxEvent::Idle,
&stats, &stats,
@ -305,11 +309,8 @@ mod tests {
let result = SfxEventMapper::map_character_event( let result = SfxEventMapper::map_character_event(
&CharacterState { &CharacterState {
action: ActionState::Roll { action_state: ActionState::Dodge(Roll(RollHandler::default())),
time_left: Duration::new(1, 0), move_state: MoveState::Run(RunHandler),
was_wielding: false,
},
movement: MovementState::Run,
}, },
SfxEvent::Run, SfxEvent::Run,
&stats, &stats,
@ -324,8 +325,8 @@ mod tests {
let result = SfxEventMapper::map_character_event( let result = SfxEventMapper::map_character_event(
&CharacterState { &CharacterState {
movement: MovementState::Fall, move_state: MoveState::Fall(FallHandler),
action: ActionState::Idle, action_state: ActionState::Idle,
}, },
SfxEvent::Idle, SfxEvent::Idle,
&stats, &stats,
@ -340,8 +341,8 @@ mod tests {
let result = SfxEventMapper::map_character_event( let result = SfxEventMapper::map_character_event(
&CharacterState { &CharacterState {
movement: MovementState::Glide, move_state: MoveState::Glide(GlideHandler),
action: ActionState::Idle, action_state: ActionState::Idle,
}, },
SfxEvent::Jump, SfxEvent::Jump,
&stats, &stats,
@ -356,8 +357,8 @@ mod tests {
let result = SfxEventMapper::map_character_event( let result = SfxEventMapper::map_character_event(
&CharacterState { &CharacterState {
movement: MovementState::Glide, move_state: MoveState::Glide(GlideHandler),
action: ActionState::Idle, action_state: ActionState::Idle,
}, },
SfxEvent::Glide, SfxEvent::Glide,
&stats, &stats,
@ -372,8 +373,8 @@ mod tests {
let result = SfxEventMapper::map_character_event( let result = SfxEventMapper::map_character_event(
&CharacterState { &CharacterState {
movement: MovementState::Fall, move_state: MoveState::Fall(FallHandler),
action: ActionState::Idle, action_state: ActionState::Idle,
}, },
SfxEvent::Glide, SfxEvent::Glide,
&stats, &stats,
@ -393,11 +394,8 @@ mod tests {
let result = SfxEventMapper::map_character_event( let result = SfxEventMapper::map_character_event(
&CharacterState { &CharacterState {
movement: MovementState::Stand, move_state: MoveState::Stand(StandHandler),
action: ActionState::Attack { action_state: ActionState::Attack(BasicAttack(BasicAttackHandler::default())),
time_left: Duration::new(1, 0),
applied: true,
},
}, },
SfxEvent::Idle, SfxEvent::Idle,
&stats, &stats,

View File

@ -6,7 +6,7 @@ use crate::{
}; };
use common::{ use common::{
assets::watch::ReloadIndicator, assets::watch::ReloadIndicator,
comp::{ActionState, Body, CharacterState, Equipment, MovementState}, comp::{ActionState, Body, CharacterState, Equipment, MoveState},
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use std::mem::{discriminant, Discriminant}; use std::mem::{discriminant, Discriminant};
@ -24,15 +24,15 @@ enum FigureKey {
#[derive(PartialEq, Eq, Hash, Clone)] #[derive(PartialEq, Eq, Hash, Clone)]
struct CharacterStateCacheKey { struct CharacterStateCacheKey {
movement: Discriminant<MovementState>, move_state: Discriminant<MoveState>,
action: Discriminant<ActionState>, action: Discriminant<ActionState>,
} }
impl From<&CharacterState> for CharacterStateCacheKey { impl From<&CharacterState> for CharacterStateCacheKey {
fn from(cs: &CharacterState) -> Self { fn from(cs: &CharacterState) -> Self {
Self { Self {
movement: discriminant(&cs.movement), move_state: discriminant(&cs.move_state),
action: discriminant(&cs.action), action: discriminant(&cs.action_state),
} }
} }
} }
@ -132,7 +132,7 @@ impl FigureModelCache {
}, },
if camera_mode == CameraMode::FirstPerson if camera_mode == CameraMode::FirstPerson
&& character_state && character_state
.map(|cs| cs.action.is_roll()) .map(|cs| cs.action_state.is_dodging())
.unwrap_or_default() .unwrap_or_default()
{ {
None None
@ -140,7 +140,7 @@ impl FigureModelCache {
Some(humanoid_armor_hand_spec.mesh_left_hand(&body)) Some(humanoid_armor_hand_spec.mesh_left_hand(&body))
}, },
if character_state if character_state
.map(|cs| cs.action.is_roll()) .map(|cs| cs.action_state.is_dodging())
.unwrap_or_default() .unwrap_or_default()
{ {
None None
@ -162,9 +162,9 @@ impl FigureModelCache {
if camera_mode != CameraMode::FirstPerson if camera_mode != CameraMode::FirstPerson
|| character_state || character_state
.map(|cs| { .map(|cs| {
cs.action.is_attack() cs.action_state.is_attacking()
|| cs.action.is_block() || cs.action_state.is_blocking()
|| cs.action.is_wield() || cs.action_state.is_wielding()
}) })
.unwrap_or_default() .unwrap_or_default()
{ {

View File

@ -18,8 +18,8 @@ use crate::{
use client::Client; use client::Client;
use common::{ use common::{
comp::{ comp::{
ActionState::*, Body, CharacterState, ItemKind, Last, MovementState::*, Ori, Pos, Scale, ActionState::*, AttackKind::*, Body, CharacterState, ItemKind, Last, MoveState::*, Ori,
Stats, Vel, Pos, Scale, Stats, Vel,
}, },
terrain::TerrainChunk, terrain::TerrainChunk,
vol::RectRasterableVol, vol::RectRasterableVol,
@ -160,7 +160,7 @@ impl FigureMgr {
) )
.1; .1;
let mut movement_animation_rate = 1.0; let mut move_state_animation_rate = 1.0;
let mut action_animation_rate = 1.0; let mut action_animation_rate = 1.0;
let vel = ecs let vel = ecs
@ -189,65 +189,65 @@ impl FigureMgr {
_ => continue, _ => continue,
}; };
if !character.is_same_movement(&last_character.0) { if !character.is_same_move_state(&last_character.0) {
state.movement_time = 0.0; state.move_state_time = 0.0;
} }
if !character.is_same_action(&last_character.0) { if !character.is_same_action_state(&last_character.0) {
state.action_time = 0.0; state.action_time = 0.0;
} }
let target_base = match &character.movement { let target_base = match &character.move_state {
Stand(_) => anim::character::StandAnimation::update_skeleton( Stand(_) => anim::character::StandAnimation::update_skeleton(
&CharacterSkeleton::new(), &CharacterSkeleton::new(),
(active_tool_kind, time), (active_tool_kind, time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Run(_) => anim::character::RunAnimation::update_skeleton( Run(_) => anim::character::RunAnimation::update_skeleton(
&CharacterSkeleton::new(), &CharacterSkeleton::new(),
(active_tool_kind, vel.0, ori.0, state.last_ori, time), (active_tool_kind, vel.0, ori.0, state.last_ori, time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Jump(_) | Fall(_) => anim::character::JumpAnimation::update_skeleton( Jump(_) | Fall(_) => anim::character::JumpAnimation::update_skeleton(
&CharacterSkeleton::new(), &CharacterSkeleton::new(),
(active_tool_kind, time), (active_tool_kind, time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Glide(_) => anim::character::GlidingAnimation::update_skeleton( Glide(_) => anim::character::GlidingAnimation::update_skeleton(
&CharacterSkeleton::new(), &CharacterSkeleton::new(),
(active_tool_kind, vel.0, ori.0, state.last_ori, time), (active_tool_kind, vel.0, ori.0, state.last_ori, time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Swim(_) => anim::character::SwimAnimation::update_skeleton( Swim(_) => anim::character::SwimAnimation::update_skeleton(
&CharacterSkeleton::new(), &CharacterSkeleton::new(),
(active_tool_kind, vel.0.magnitude(), ori.0.magnitude(), time), (active_tool_kind, vel.0.magnitude(), ori.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Climb(_) => anim::character::ClimbAnimation::update_skeleton( Climb(_) => anim::character::ClimbAnimation::update_skeleton(
&CharacterSkeleton::new(), &CharacterSkeleton::new(),
(active_tool_kind, vel.0, ori.0, time), (active_tool_kind, vel.0, ori.0, time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Sit(_) => anim::character::SitAnimation::update_skeleton( Sit(_) => anim::character::SitAnimation::update_skeleton(
&CharacterSkeleton::new(), &CharacterSkeleton::new(),
(active_tool_kind, time), (active_tool_kind, time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
}; };
let target_bones = match (&character.movement, &character.action) { let target_bones = match (&character.move_state, &character.action_state) {
(Stand(_), Wield { .. }) => { (Stand(_), Wield { .. }) => {
anim::character::CidleAnimation::update_skeleton( anim::character::CidleAnimation::update_skeleton(
&target_base, &target_base,
@ -266,35 +266,37 @@ impl FigureMgr {
skeleton_attr, skeleton_attr,
) )
} }
(_, Attack { .. }) => anim::character::AttackAnimation::update_skeleton( (_, Attack(kind)) => match kind {
&target_base, Charge(_) => anim::character::ChargeAnimation::update_skeleton(
(active_tool_kind, time), &target_base,
state.action_time, (active_tool_kind, time),
&mut action_animation_rate, state.action_time,
skeleton_attr, &mut action_animation_rate,
), skeleton_attr,
(_, Wield { .. }) => anim::character::WieldAnimation::update_skeleton( ),
BasicAttack(_) => anim::character::AttackAnimation::update_skeleton(
&target_base,
(active_tool_kind, time),
state.action_time,
&mut action_animation_rate,
skeleton_attr,
),
},
(_, Wield(_)) => anim::character::WieldAnimation::update_skeleton(
&target_base, &target_base,
(active_tool_kind, vel.0.magnitude(), time), (active_tool_kind, vel.0.magnitude(), time),
state.action_time, state.action_time,
&mut action_animation_rate, &mut action_animation_rate,
skeleton_attr, skeleton_attr,
), ),
(_, Roll { .. }) => anim::character::RollAnimation::update_skeleton( (_, Dodge(_)) => anim::character::RollAnimation::update_skeleton(
&target_base, &target_base,
(active_tool_kind, time), (active_tool_kind, time),
state.action_time, state.action_time,
&mut action_animation_rate, &mut action_animation_rate,
skeleton_attr, skeleton_attr,
), ),
(_, Block { .. }) => anim::character::BlockAnimation::update_skeleton( (_, Block(_)) => anim::character::BlockAnimation::update_skeleton(
&target_base,
(active_tool_kind, time),
state.action_time,
&mut action_animation_rate,
skeleton_attr,
),
(_, Charge { .. }) => anim::character::ChargeAnimation::update_skeleton(
&target_base, &target_base,
(active_tool_kind, time), (active_tool_kind, time),
state.action_time, state.action_time,
@ -313,7 +315,7 @@ impl FigureMgr {
scale, scale,
col, col,
dt, dt,
movement_animation_rate, move_state_animation_rate,
action_animation_rate, action_animation_rate,
); );
} }
@ -330,30 +332,30 @@ impl FigureMgr {
_ => continue, _ => continue,
}; };
if !character.is_same_movement(&last_character.0) { if !character.is_same_move_state(&last_character.0) {
state.movement_time = 0.0; state.move_state_time = 0.0;
} }
let target_base = match character.movement { let target_base = match character.move_state {
Stand(_) => anim::quadruped_small::IdleAnimation::update_skeleton( Stand(_) => anim::quadruped_small::IdleAnimation::update_skeleton(
&QuadrupedSmallSkeleton::new(), &QuadrupedSmallSkeleton::new(),
time, time,
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Run(_) => anim::quadruped_small::RunAnimation::update_skeleton( Run(_) => anim::quadruped_small::RunAnimation::update_skeleton(
&QuadrupedSmallSkeleton::new(), &QuadrupedSmallSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Jump(_) => anim::quadruped_small::JumpAnimation::update_skeleton( Jump(_) => anim::quadruped_small::JumpAnimation::update_skeleton(
&QuadrupedSmallSkeleton::new(), &QuadrupedSmallSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
@ -370,7 +372,7 @@ impl FigureMgr {
scale, scale,
col, col,
dt, dt,
movement_animation_rate, move_state_animation_rate,
action_animation_rate, action_animation_rate,
); );
} }
@ -387,30 +389,30 @@ impl FigureMgr {
_ => continue, _ => continue,
}; };
if !character.is_same_movement(&last_character.0) { if !character.is_same_move_state(&last_character.0) {
state.movement_time = 0.0; state.move_state_time = 0.0;
} }
let target_base = match character.movement { let target_base = match character.move_state {
Stand(_) => anim::quadruped_medium::IdleAnimation::update_skeleton( Stand(_) => anim::quadruped_medium::IdleAnimation::update_skeleton(
&QuadrupedMediumSkeleton::new(), &QuadrupedMediumSkeleton::new(),
time, time,
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Run(_) => anim::quadruped_medium::RunAnimation::update_skeleton( Run(_) => anim::quadruped_medium::RunAnimation::update_skeleton(
&QuadrupedMediumSkeleton::new(), &QuadrupedMediumSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Jump(_) => anim::quadruped_medium::JumpAnimation::update_skeleton( Jump(_) => anim::quadruped_medium::JumpAnimation::update_skeleton(
&QuadrupedMediumSkeleton::new(), &QuadrupedMediumSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
@ -427,7 +429,7 @@ impl FigureMgr {
scale, scale,
col, col,
dt, dt,
movement_animation_rate, move_state_animation_rate,
action_animation_rate, action_animation_rate,
); );
} }
@ -442,30 +444,30 @@ impl FigureMgr {
_ => continue, _ => continue,
}; };
if !character.is_same_movement(&last_character.0) { if !character.is_same_move_state(&last_character.0) {
state.movement_time = 0.0; state.move_state_time = 0.0;
} }
let target_base = match character.movement { let target_base = match character.move_state {
Stand(_) => anim::bird_medium::IdleAnimation::update_skeleton( Stand(_) => anim::bird_medium::IdleAnimation::update_skeleton(
&BirdMediumSkeleton::new(), &BirdMediumSkeleton::new(),
time, time,
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Run(_) => anim::bird_medium::RunAnimation::update_skeleton( Run(_) => anim::bird_medium::RunAnimation::update_skeleton(
&BirdMediumSkeleton::new(), &BirdMediumSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Jump(_) => anim::bird_medium::JumpAnimation::update_skeleton( Jump(_) => anim::bird_medium::JumpAnimation::update_skeleton(
&BirdMediumSkeleton::new(), &BirdMediumSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
@ -482,7 +484,7 @@ impl FigureMgr {
scale, scale,
col, col,
dt, dt,
movement_animation_rate, move_state_animation_rate,
action_animation_rate, action_animation_rate,
); );
} }
@ -497,30 +499,30 @@ impl FigureMgr {
_ => continue, _ => continue,
}; };
if !character.is_same_movement(&last_character.0) { if !character.is_same_move_state(&last_character.0) {
state.movement_time = 0.0; state.move_state_time = 0.0;
} }
let target_base = match character.movement { let target_base = match character.move_state {
Stand(_) => anim::fish_medium::IdleAnimation::update_skeleton( Stand(_) => anim::fish_medium::IdleAnimation::update_skeleton(
&FishMediumSkeleton::new(), &FishMediumSkeleton::new(),
time, time,
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Run(_) => anim::fish_medium::RunAnimation::update_skeleton( Run(_) => anim::fish_medium::RunAnimation::update_skeleton(
&FishMediumSkeleton::new(), &FishMediumSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Jump(_) => anim::fish_medium::JumpAnimation::update_skeleton( Jump(_) => anim::fish_medium::JumpAnimation::update_skeleton(
&FishMediumSkeleton::new(), &FishMediumSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
@ -537,7 +539,7 @@ impl FigureMgr {
scale, scale,
col, col,
dt, dt,
movement_animation_rate, move_state_animation_rate,
action_animation_rate, action_animation_rate,
); );
} }
@ -552,30 +554,30 @@ impl FigureMgr {
_ => continue, _ => continue,
}; };
if !character.is_same_movement(&last_character.0) { if !character.is_same_move_state(&last_character.0) {
state.movement_time = 0.0; state.move_state_time = 0.0;
} }
let target_base = match character.movement { let target_base = match character.move_state {
Stand(_) => anim::dragon::IdleAnimation::update_skeleton( Stand(_) => anim::dragon::IdleAnimation::update_skeleton(
&DragonSkeleton::new(), &DragonSkeleton::new(),
time, time,
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Run(_) => anim::dragon::RunAnimation::update_skeleton( Run(_) => anim::dragon::RunAnimation::update_skeleton(
&DragonSkeleton::new(), &DragonSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Jump(_) => anim::dragon::JumpAnimation::update_skeleton( Jump(_) => anim::dragon::JumpAnimation::update_skeleton(
&DragonSkeleton::new(), &DragonSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
@ -592,7 +594,7 @@ impl FigureMgr {
scale, scale,
col, col,
dt, dt,
movement_animation_rate, move_state_animation_rate,
action_animation_rate, action_animation_rate,
); );
} }
@ -607,30 +609,30 @@ impl FigureMgr {
_ => continue, _ => continue,
}; };
if !character.is_same_movement(&last_character.0) { if !character.is_same_move_state(&last_character.0) {
state.movement_time = 0.0; state.move_state_time = 0.0;
} }
let target_base = match character.movement { let target_base = match character.move_state {
Stand(_) => anim::bird_small::IdleAnimation::update_skeleton( Stand(_) => anim::bird_small::IdleAnimation::update_skeleton(
&BirdSmallSkeleton::new(), &BirdSmallSkeleton::new(),
time, time,
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Run(_) => anim::bird_small::RunAnimation::update_skeleton( Run(_) => anim::bird_small::RunAnimation::update_skeleton(
&BirdSmallSkeleton::new(), &BirdSmallSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Jump(_) => anim::bird_small::JumpAnimation::update_skeleton( Jump(_) => anim::bird_small::JumpAnimation::update_skeleton(
&BirdSmallSkeleton::new(), &BirdSmallSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
@ -647,7 +649,7 @@ impl FigureMgr {
scale, scale,
col, col,
dt, dt,
movement_animation_rate, move_state_animation_rate,
action_animation_rate, action_animation_rate,
); );
} }
@ -662,30 +664,30 @@ impl FigureMgr {
_ => continue, _ => continue,
}; };
if !character.is_same_movement(&last_character.0) { if !character.is_same_move_state(&last_character.0) {
state.movement_time = 0.0; state.move_state_time = 0.0;
} }
let target_base = match character.movement { let target_base = match character.move_state {
Stand(_) => anim::fish_small::IdleAnimation::update_skeleton( Stand(_) => anim::fish_small::IdleAnimation::update_skeleton(
&FishSmallSkeleton::new(), &FishSmallSkeleton::new(),
time, time,
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Run(_) => anim::fish_small::RunAnimation::update_skeleton( Run(_) => anim::fish_small::RunAnimation::update_skeleton(
&FishSmallSkeleton::new(), &FishSmallSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Jump(_) => anim::fish_small::JumpAnimation::update_skeleton( Jump(_) => anim::fish_small::JumpAnimation::update_skeleton(
&FishSmallSkeleton::new(), &FishSmallSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
@ -702,7 +704,7 @@ impl FigureMgr {
scale, scale,
col, col,
dt, dt,
movement_animation_rate, move_state_animation_rate,
action_animation_rate, action_animation_rate,
); );
} }
@ -717,30 +719,30 @@ impl FigureMgr {
_ => continue, _ => continue,
}; };
if !character.is_same_movement(&last_character.0) { if !character.is_same_move_state(&last_character.0) {
state.movement_time = 0.0; state.move_state_time = 0.0;
} }
let target_base = match character.movement { let target_base = match character.move_state {
Stand(_) => anim::biped_large::IdleAnimation::update_skeleton( Stand(_) => anim::biped_large::IdleAnimation::update_skeleton(
&BipedLargeSkeleton::new(), &BipedLargeSkeleton::new(),
time, time,
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Run(_) => anim::biped_large::RunAnimation::update_skeleton( Run(_) => anim::biped_large::RunAnimation::update_skeleton(
&BipedLargeSkeleton::new(), &BipedLargeSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
Jump(_) => anim::biped_large::JumpAnimation::update_skeleton( Jump(_) => anim::biped_large::JumpAnimation::update_skeleton(
&BipedLargeSkeleton::new(), &BipedLargeSkeleton::new(),
(vel.0.magnitude(), time), (vel.0.magnitude(), time),
state.movement_time, state.move_state_time,
&mut movement_animation_rate, &mut move_state_animation_rate,
skeleton_attr, skeleton_attr,
), ),
@ -757,7 +759,7 @@ impl FigureMgr {
scale, scale,
col, col,
dt, dt,
movement_animation_rate, move_state_animation_rate,
action_animation_rate, action_animation_rate,
); );
} }
@ -776,7 +778,7 @@ impl FigureMgr {
scale, scale,
col, col,
dt, dt,
movement_animation_rate, move_state_animation_rate,
action_animation_rate, action_animation_rate,
); );
} }
@ -919,7 +921,7 @@ impl FigureMgr {
pub struct FigureState<S: Skeleton> { pub struct FigureState<S: Skeleton> {
bone_consts: Consts<FigureBoneData>, bone_consts: Consts<FigureBoneData>,
locals: Consts<FigureLocals>, locals: Consts<FigureLocals>,
movement_time: f64, move_state_time: f64,
action_time: f64, action_time: f64,
skeleton: S, skeleton: S,
pos: Vec3<f32>, pos: Vec3<f32>,
@ -934,7 +936,7 @@ impl<S: Skeleton> FigureState<S> {
.create_consts(&skeleton.compute_matrices()) .create_consts(&skeleton.compute_matrices())
.unwrap(), .unwrap(),
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(), locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
movement_time: 0.0, move_state_time: 0.0,
action_time: 0.0, action_time: 0.0,
skeleton, skeleton,
pos: Vec3::zero(), pos: Vec3::zero(),
@ -952,7 +954,7 @@ impl<S: Skeleton> FigureState<S> {
scale: f32, scale: f32,
col: Rgba<f32>, col: Rgba<f32>,
dt: f32, dt: f32,
movement_rate: f32, move_state_rate: f32,
action_rate: f32, action_rate: f32,
) { ) {
self.last_ori = Lerp::lerp(self.last_ori, ori, 15.0 * dt); self.last_ori = Lerp::lerp(self.last_ori, ori, 15.0 * dt);
@ -966,7 +968,7 @@ impl<S: Skeleton> FigureState<S> {
self.ori = ori; self.ori = ori;
} }
self.movement_time += (dt * movement_rate) as f64; self.move_state_time += (dt * move_state_rate) as f64;
self.action_time += (dt * action_rate) as f64; self.action_time += (dt * action_rate) as f64;
let mat = Mat4::<f32>::identity() let mat = Mat4::<f32>::identity()

View File

@ -160,7 +160,7 @@ impl Scene {
.ecs() .ecs()
.read_storage::<comp::CharacterState>() .read_storage::<comp::CharacterState>()
.get(client.entity()) .get(client.entity())
.map_or(false, |cs| cs.action.is_roll()); .map_or(false, |cs| cs.action_state.is_dodging());
let player_scale = match client let player_scale = match client
.state() .state()

View File

@ -202,9 +202,9 @@ impl PlayState for SessionState {
.read_storage::<comp::CharacterState>() .read_storage::<comp::CharacterState>()
.get(client.entity()) .get(client.entity())
.map(|cs| { .map(|cs| {
cs.action.is_wield() cs.action_state.is_wielding()
|| cs.action.is_block() || cs.action_state.is_blocking()
|| cs.action.is_attack() || cs.action_state.is_attacking()
}) })
.unwrap_or(false) .unwrap_or(false)
{ {