Finish state struct data refactor

This commit is contained in:
AdamWhitehurst 2020-03-14 15:17:27 -06:00
parent ee706fa32a
commit 7dfe00b674
16 changed files with 417 additions and 359 deletions

View File

@ -39,23 +39,25 @@ impl From<CharacterAbility> for CharacterState {
CharacterAbility::BasicAttack { CharacterAbility::BasicAttack {
buildup_duration, buildup_duration,
recover_duration, recover_duration,
} => CharacterState::BasicAttack(basic_attack::State { } => CharacterState::BasicAttack(basic_attack::Data {
exhausted: false, exhausted: false,
buildup_duration, buildup_duration,
recover_duration, recover_duration,
}), }),
CharacterAbility::BasicBlock { .. } => CharacterState::BasicBlock {}, CharacterAbility::BasicBlock { .. } => CharacterState::BasicBlock,
CharacterAbility::Roll { .. } => CharacterState::Roll { CharacterAbility::Roll { .. } => CharacterState::Roll(roll::Data {
remaining_duration: Duration::from_millis(600), remaining_duration: Duration::from_millis(600),
}, }),
CharacterAbility::ChargeAttack { .. } => CharacterState::ChargeAttack { CharacterAbility::ChargeAttack { .. } => {
CharacterState::ChargeAttack(charge_attack::Data {
remaining_duration: Duration::from_millis(600), remaining_duration: Duration::from_millis(600),
})
}, },
CharacterAbility::TimedCombo { CharacterAbility::TimedCombo {
tool, tool,
buildup_duration, buildup_duration,
recover_duration, recover_duration,
} => CharacterState::TimedCombo(timed_combo::State { } => CharacterState::TimedCombo(timed_combo::Data {
tool, tool,
buildup_duration, buildup_duration,
recover_duration, recover_duration,

View File

@ -5,7 +5,7 @@ use crate::{
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::{Component, FlaggedStorage, HashMapStorage, VecStorage}; use specs::{Component, FlaggedStorage, HashMapStorage, VecStorage};
use std::{collections::VecDeque, time::Duration}; use std::collections::VecDeque;
/// Data returned from character behavior fn's to Character Behavior System. /// Data returned from character behavior fn's to Character Behavior System.
pub struct StateUpdate { pub struct StateUpdate {
@ -22,54 +22,35 @@ pub struct StateUpdate {
pub enum CharacterState { pub enum CharacterState {
Idle, Idle,
Climb, Climb,
Sit {}, Sit,
Equipping {
/// The weapon being equipped
tool: ToolData,
/// Time left before next state
time_left: Duration,
},
Wielding {
/// The weapon being wielded
tool: ToolData,
},
Glide, Glide,
/// A basic blocking state /// A basic blocking state
BasicBlock, BasicBlock,
ChargeAttack { /// Player is busy equipping or unequipping weapons
/// How long the state has until exiting Equipping(equipping::Data),
remaining_duration: Duration, /// Player is holding a weapon and can perform other actions
}, Wielding(wielding::Data),
Roll { /// Player rushes forward and slams an enemy with their weapon
/// How long the state has until exiting ChargeAttack(charge_attack::Data),
remaining_duration: Duration, /// A dodge where player can roll
}, Roll(roll::Data),
/// A basic attacking state /// A basic attacking state
BasicAttack(basic_attack::State), BasicAttack(basic_attack::Data),
/// A three-stage attack where play must click at appropriate times /// A three-stage attack where play must click at appropriate times
/// to continue attack chain. /// to continue attack chain.
TimedCombo(timed_combo::State), TimedCombo(timed_combo::Data),
/// A three-stage attack where each attack pushes player forward /// A three-stage attack where each attack pushes player forward
/// and successive attacks increase in damage, while player holds button. /// and successive attacks increase in damage, while player holds button.
TripleStrike { TripleStrike(triple_strike::Data),
/// The tool this state will read to handle damage, etc.
tool: ToolData,
/// `int` denoting what stage (of 3) the attack is in.
stage: i8,
/// How long current stage has been active
stage_time_active: Duration,
/// Whether current stage has exhausted its attack
stage_exhausted: bool,
},
} }
impl CharacterState { impl CharacterState {
pub fn is_wield(&self) -> bool { pub fn is_wield(&self) -> bool {
match self { match self {
CharacterState::Wielding { .. } CharacterState::Wielding(_)
| CharacterState::BasicAttack(_) | CharacterState::BasicAttack(_)
| CharacterState::TimedCombo(_) | CharacterState::TimedCombo(_)
| CharacterState::BasicBlock { .. } => true, | CharacterState::BasicBlock => true,
_ => false, _ => false,
} }
} }
@ -78,21 +59,21 @@ impl CharacterState {
match self { match self {
CharacterState::BasicAttack(_) CharacterState::BasicAttack(_)
| CharacterState::TimedCombo(_) | CharacterState::TimedCombo(_)
| CharacterState::ChargeAttack { .. } => true, | CharacterState::ChargeAttack(_) => true,
_ => false, _ => false,
} }
} }
pub fn is_block(&self) -> bool { pub fn is_block(&self) -> bool {
match self { match self {
CharacterState::BasicBlock { .. } => true, CharacterState::BasicBlock => true,
_ => false, _ => false,
} }
} }
pub fn is_dodge(&self) -> bool { pub fn is_dodge(&self) -> bool {
match self { match self {
CharacterState::Roll { .. } => true, CharacterState::Roll(_) => true,
_ => false, _ => false,
} }
} }
@ -105,7 +86,7 @@ impl CharacterState {
} }
impl Default for CharacterState { impl Default for CharacterState {
fn default() -> Self { Self::Idle {} } fn default() -> Self { Self::Idle }
} }
impl Component for CharacterState { impl Component for CharacterState {

View File

@ -1,12 +1,12 @@
use crate::{ use crate::{
comp::{Attacking, CharacterState, EnergySource, ItemKind::Tool, StateUpdate}, comp::{Attacking, CharacterState, EnergySource, StateUpdate},
states::utils::*, states::{utils::*, wielding},
sys::character_behavior::*, sys::character_behavior::*,
}; };
use std::{collections::VecDeque, time::Duration}; use std::{collections::VecDeque, time::Duration};
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct State { pub struct Data {
/// How long until state should deal damage /// How long until state should deal damage
pub buildup_duration: Duration, pub buildup_duration: Duration,
/// How long the state has until exiting /// How long the state has until exiting
@ -15,7 +15,7 @@ pub struct State {
pub exhausted: bool, pub exhausted: bool,
} }
impl CharacterBehavior for State { impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate { fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
pos: *data.pos, pos: *data.pos,
@ -32,7 +32,7 @@ impl CharacterBehavior for State {
// Build up window // Build up window
if self.buildup_duration != Duration::default() { if self.buildup_duration != Duration::default() {
// Start to swing // Start to swing
update.character = CharacterState::BasicAttack(State { update.character = CharacterState::BasicAttack(Data {
buildup_duration: self buildup_duration: self
.buildup_duration .buildup_duration
.checked_sub(Duration::from_secs_f32(data.dt.0)) .checked_sub(Duration::from_secs_f32(data.dt.0))
@ -52,7 +52,7 @@ impl CharacterBehavior for State {
}); });
} }
update.character = CharacterState::BasicAttack(State { update.character = CharacterState::BasicAttack(Data {
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
recover_duration: self.recover_duration, recover_duration: self.recover_duration,
exhausted: true, exhausted: true,
@ -60,7 +60,7 @@ impl CharacterBehavior for State {
} }
// Swing recovery window // Swing recovery window
else if self.recover_duration != Duration::default() { else if self.recover_duration != Duration::default() {
update.character = CharacterState::BasicAttack(State { update.character = CharacterState::BasicAttack(Data {
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
recover_duration: self recover_duration: self
.recover_duration .recover_duration
@ -72,7 +72,7 @@ impl CharacterBehavior for State {
// Done // Done
else { else {
if let Some(tool) = unwrap_tool_data(data) { if let Some(tool) = unwrap_tool_data(data) {
update.character = CharacterState::Wielding { tool }; update.character = CharacterState::Wielding(wielding::Data { tool });
// Make sure attack component is removed // Make sure attack component is removed
data.updater.remove::<Attacking>(data.entity); data.updater.remove::<Attacking>(data.entity);
} else { } else {

View File

@ -1,11 +1,18 @@
use super::utils::*; use super::utils::*;
use crate::{comp::StateUpdate, sys::character_behavior::JoinData}; use crate::{
comp::StateUpdate,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use std::collections::VecDeque; use std::collections::VecDeque;
// const BLOCK_ACCEL: f32 = 30.0; // const BLOCK_ACCEL: f32 = 30.0;
// const BLOCK_SPEED: f32 = 75.0; // const BLOCK_SPEED: f32 = 75.0;
pub fn behavior(data: &JoinData) -> StateUpdate { #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
pos: *data.pos, pos: *data.pos,
vel: *data.vel, vel: *data.vel,
@ -23,3 +30,4 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
} }
update update
} }
}

View File

@ -2,14 +2,21 @@ use super::utils::*;
use crate::{ use crate::{
comp::{CharacterState::*, HealthChange, HealthSource, StateUpdate}, comp::{CharacterState::*, HealthChange, HealthSource, StateUpdate},
event::ServerEvent, event::ServerEvent,
sys::character_behavior::JoinData, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use std::{collections::VecDeque, time::Duration}; use std::{collections::VecDeque, time::Duration};
use vek::Vec3; use vek::Vec3;
const CHARGE_SPEED: f32 = 20.0; const CHARGE_SPEED: f32 = 20.0;
pub fn behavior(data: &JoinData) -> StateUpdate { #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data {
/// How long the state has until exiting
pub remaining_duration: Duration,
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
pos: *data.pos, pos: *data.pos,
vel: *data.vel, vel: *data.vel,
@ -19,8 +26,6 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
local_events: VecDeque::new(), local_events: VecDeque::new(),
server_events: VecDeque::new(), server_events: VecDeque::new(),
}; };
if let ChargeAttack { remaining_duration } = data.character {
// Move player // Move player
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z) update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
+ (update.vel.0 * Vec3::new(1.0, 1.0, 0.0) + (update.vel.0 * Vec3::new(1.0, 1.0, 0.0)
@ -46,18 +51,20 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
} }
// Check if charge timed out or can't keep moving forward // Check if charge timed out or can't keep moving forward
if *remaining_duration == Duration::default() || update.vel.0.magnitude_squared() < 10.0 { if self.remaining_duration == Duration::default() || update.vel.0.magnitude_squared() < 10.0
{
attempt_wield(data, &mut update); attempt_wield(data, &mut update);
return update; return update;
} }
// Tick remaining-duration and keep charging // Tick remaining-duration and keep charging
update.character = ChargeAttack { update.character = ChargeAttack(Data {
remaining_duration: remaining_duration remaining_duration: self
.remaining_duration
.checked_sub(Duration::from_secs_f32(data.dt.0)) .checked_sub(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(), .unwrap_or_default(),
}; });
}
update update
} }
}

View File

@ -1,7 +1,10 @@
use crate::{ use crate::{
comp::{CharacterState, EnergySource, StateUpdate}, comp::{CharacterState, EnergySource, StateUpdate},
event::LocalEvent, event::LocalEvent,
sys::{character_behavior::JoinData, phys::GRAVITY}, sys::{
character_behavior::{CharacterBehavior, JoinData},
phys::GRAVITY,
},
}; };
use std::collections::VecDeque; use std::collections::VecDeque;
use vek::{ use vek::{
@ -12,7 +15,11 @@ use vek::{
const HUMANOID_CLIMB_ACCEL: f32 = 5.0; const HUMANOID_CLIMB_ACCEL: f32 = 5.0;
const CLIMB_SPEED: f32 = 5.0; const CLIMB_SPEED: f32 = 5.0;
pub fn behavior(data: &JoinData) -> StateUpdate { #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
pos: *data.pos, pos: *data.pos,
vel: *data.vel, vel: *data.vel,
@ -78,7 +85,8 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
data.physics.on_wall, data.physics.on_wall,
) { ) {
if data.inputs.climb_down.is_pressed() && !data.inputs.climb.is_pressed() { 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); 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() { } 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); update.vel.0.z = (update.vel.0.z + data.dt.0 * GRAVITY * 1.25).min(CLIMB_SPEED);
} else { } else {
@ -93,3 +101,4 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
update update
} }
}

View File

@ -1,11 +1,21 @@
use super::utils::*; use super::utils::*;
use crate::{ use crate::{
comp::{CharacterState, StateUpdate}, comp::{CharacterState, StateUpdate, ToolData},
sys::character_behavior::JoinData, states::wielding,
sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use std::{collections::VecDeque, time::Duration}; use std::{collections::VecDeque, time::Duration};
pub fn behavior(data: &JoinData) -> StateUpdate { #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data {
/// The weapon being equipped
pub tool: ToolData,
/// Time left before next state
pub time_left: Duration,
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *data.character, character: *data.character,
pos: *data.pos, pos: *data.pos,
@ -19,20 +29,21 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
handle_move(&data, &mut update); handle_move(&data, &mut update);
handle_jump(&data, &mut update); handle_jump(&data, &mut update);
if let CharacterState::Equipping { tool, time_left } = data.character { if self.time_left == Duration::default() {
if *time_left == Duration::default() {
// Wield delay has expired // Wield delay has expired
update.character = CharacterState::Wielding { tool: *tool }; update.character = CharacterState::Wielding(wielding::Data { tool: self.tool });
} else { } else {
// Wield delay hasn't expired yet // Wield delay hasn't expired yet
// Update wield delay // Update wield delay
update.character = CharacterState::Equipping { update.character = CharacterState::Equipping(Data {
time_left: time_left time_left: self
.time_left
.checked_sub(Duration::from_secs_f32(data.dt.0)) .checked_sub(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(), .unwrap_or_default(),
tool: *tool, tool: self.tool,
}; });
}
} }
update update
} }
}

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
comp::{CharacterState, StateUpdate}, comp::{CharacterState, StateUpdate},
sys::character_behavior::JoinData, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use std::collections::VecDeque; use std::collections::VecDeque;
use vek::{Vec2, Vec3}; use vek::{Vec2, Vec3};
@ -10,7 +10,11 @@ const GLIDE_ANTIGRAV: f32 = crate::sys::phys::GRAVITY * 0.96;
const GLIDE_ACCEL: f32 = 15.0; const GLIDE_ACCEL: f32 = 15.0;
const GLIDE_SPEED: f32 = 45.0; const GLIDE_SPEED: f32 = 45.0;
pub fn behavior(data: &JoinData) -> StateUpdate { #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
pos: *data.pos, pos: *data.pos,
vel: *data.vel, vel: *data.vel,
@ -64,3 +68,4 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
// Otherwise keep gliding // Otherwise keep gliding
update update
} }
}

View File

@ -1,8 +1,14 @@
use super::utils::*; use super::utils::*;
use crate::{comp::StateUpdate, sys::character_behavior::JoinData}; use crate::{
comp::StateUpdate,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use std::collections::VecDeque; use std::collections::VecDeque;
pub fn behavior(data: &JoinData) -> StateUpdate { pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *data.character, character: *data.character,
pos: *data.pos, pos: *data.pos,
@ -22,3 +28,4 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
update update
} }
}

View File

@ -1,13 +1,19 @@
use crate::{ use crate::{
comp::{CharacterState, StateUpdate}, comp::{CharacterState, StateUpdate},
sys::character_behavior::JoinData, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use std::{collections::VecDeque, time::Duration}; use std::{collections::VecDeque, time::Duration};
use vek::Vec3; use vek::Vec3;
const ROLL_SPEED: f32 = 17.0; const ROLL_SPEED: f32 = 17.0;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data {
/// How long the state has until exiting
pub remaining_duration: Duration,
}
pub fn behavior(data: &JoinData) -> StateUpdate { impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *data.character, character: *data.character,
pos: *data.pos, pos: *data.pos,
@ -18,7 +24,6 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
server_events: VecDeque::new(), server_events: VecDeque::new(),
}; };
if let CharacterState::Roll { remaining_duration } = data.character {
// Update velocity // Update velocity
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z) update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
+ (update.vel.0 * Vec3::new(1.0, 1.0, 0.0) + (update.vel.0 * Vec3::new(1.0, 1.0, 0.0)
@ -37,19 +42,20 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
vek::ops::Slerp::slerp(update.ori.0, update.vel.0.into(), 9.0 * data.dt.0); vek::ops::Slerp::slerp(update.ori.0, update.vel.0.into(), 9.0 * data.dt.0);
} }
if *remaining_duration == Duration::default() { if self.remaining_duration == Duration::default() {
// Roll duration has expired // Roll duration has expired
update.vel.0 *= 0.3; update.vel.0 *= 0.3;
update.character = CharacterState::Idle {}; update.character = CharacterState::Idle {};
} else { } else {
// Otherwise, tick down remaining_duration // Otherwise, tick down remaining_duration
update.character = CharacterState::Roll { update.character = CharacterState::Roll(Data {
remaining_duration: remaining_duration remaining_duration: self
.remaining_duration
.checked_sub(Duration::from_secs_f32(data.dt.0)) .checked_sub(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(), .unwrap_or_default(),
}; });
}
} }
update update
} }
}

View File

@ -1,11 +1,15 @@
use super::utils::*; use super::utils::*;
use crate::{ use crate::{
comp::{CharacterState, StateUpdate}, comp::{CharacterState, StateUpdate},
sys::character_behavior::JoinData, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use std::collections::VecDeque; use std::collections::VecDeque;
pub fn behavior(data: &JoinData) -> StateUpdate { #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *data.character, character: *data.character,
pos: *data.pos, pos: *data.pos,
@ -23,8 +27,9 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
|| data.inputs.sit.is_just_pressed() || data.inputs.sit.is_just_pressed()
|| data.inputs.move_dir.magnitude_squared() > 0.0 || data.inputs.move_dir.magnitude_squared() > 0.0
{ {
update.character = CharacterState::Idle {}; update.character = CharacterState::Idle;
} }
update update
} }
}

View File

@ -1,11 +1,11 @@
use crate::{ use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate, ToolData}, comp::{Attacking, CharacterState, EnergySource, StateUpdate, ToolData},
states::utils::*, states::wielding,
sys::character_behavior::{CharacterBehavior, JoinData}, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use std::{collections::VecDeque, time::Duration}; use std::{collections::VecDeque, time::Duration};
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct State { pub struct Data {
/// Denotes what stage (of 3) the attack is in /// Denotes what stage (of 3) the attack is in
pub stage: i8, pub stage: i8,
/// Whether current stage has exhausted its attack /// Whether current stage has exhausted its attack
@ -20,7 +20,7 @@ pub struct State {
pub tool: ToolData, pub tool: ToolData,
} }
impl CharacterBehavior for State { impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate { fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
pos: *data.pos, pos: *data.pos,
@ -44,11 +44,11 @@ impl CharacterBehavior for State {
if data.inputs.primary.is_just_pressed() { if data.inputs.primary.is_just_pressed() {
println!("Failed"); println!("Failed");
// They failed, go back to `Wielding` // They failed, go back to `Wielding`
update.character = CharacterState::Wielding { tool: self.tool }; update.character = CharacterState::Wielding(wielding::Data { tool: self.tool });
} }
// Keep updating // Keep updating
else { else {
update.character = CharacterState::TimedCombo(State { update.character = CharacterState::TimedCombo(Data {
tool: self.tool, tool: self.tool,
stage: self.stage, stage: self.stage,
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
@ -67,7 +67,7 @@ impl CharacterBehavior for State {
hit_count: 0, hit_count: 0,
}); });
update.character = CharacterState::TimedCombo(State { update.character = CharacterState::TimedCombo(Data {
tool: self.tool, tool: self.tool,
stage: self.stage, stage: self.stage,
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
@ -86,7 +86,7 @@ impl CharacterBehavior for State {
// Try to transition to next stage // Try to transition to next stage
if data.inputs.primary.is_just_pressed() { if data.inputs.primary.is_just_pressed() {
println!("Transition"); println!("Transition");
update.character = CharacterState::TimedCombo(State { update.character = CharacterState::TimedCombo(Data {
tool: self.tool, tool: self.tool,
stage: self.stage + 1, stage: self.stage + 1,
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
@ -99,7 +99,7 @@ impl CharacterBehavior for State {
else { else {
// Update state // Update state
println!("Missed"); println!("Missed");
update.character = CharacterState::TimedCombo(State { update.character = CharacterState::TimedCombo(Data {
tool: self.tool, tool: self.tool,
stage: self.stage, stage: self.stage,
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
@ -112,7 +112,7 @@ impl CharacterBehavior for State {
// Stage expired but missed transition to next stage // Stage expired but missed transition to next stage
else { else {
// Back to `Wielding` // Back to `Wielding`
update.character = CharacterState::Wielding { tool: self.tool }; update.character = CharacterState::Wielding(wielding::Data { tool: self.tool });
// Make sure attack component is removed // Make sure attack component is removed
data.updater.remove::<Attacking>(data.entity); data.updater.remove::<Attacking>(data.entity);
} }
@ -121,7 +121,7 @@ impl CharacterBehavior for State {
else { else {
println!("Success!"); println!("Success!");
// Back to `Wielding` // Back to `Wielding`
update.character = CharacterState::Wielding { tool: self.tool }; update.character = CharacterState::Wielding(wielding::Data { tool: self.tool });
// Make sure attack component is removed // Make sure attack component is removed
data.updater.remove::<Attacking>(data.entity); data.updater.remove::<Attacking>(data.entity);
} }

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
comp::{Attacking, CharacterState, ItemKind::Tool, StateUpdate}, comp::{StateUpdate, ToolData},
states::utils::*, states::utils::*,
sys::character_behavior::JoinData, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use std::{collections::VecDeque, time::Duration}; use std::{collections::VecDeque, time::Duration};
@ -14,7 +14,20 @@ const STAGE_DURATION: u64 = 600;
/// each one pushes the player forward as the character steps into the swings. /// each one pushes the player forward as the character steps into the swings.
/// The player can let go of the left mouse button at any time /// The player can let go of the left mouse button at any time
/// and stop their attacks by interrupting the attack animation. /// and stop their attacks by interrupting the attack animation.
pub fn behavior(data: &JoinData) -> StateUpdate { #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data {
/// The tool this state will read to handle damage, etc.
pub tool: ToolData,
/// `int` denoting what stage (of 3) the attack is in.
pub stage: i8,
/// How long current stage has been active
pub stage_time_active: Duration,
/// Whether current stage has exhausted its attack
stage_exhausted: bool,
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
pos: *data.pos, pos: *data.pos,
vel: *data.vel, vel: *data.vel,
@ -25,15 +38,9 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
server_events: VecDeque::new(), server_events: VecDeque::new(),
}; };
if let CharacterState::TripleStrike { let new_stage_exhausted = self.stage_exhausted;
tool, let new_stage_time_active = self
stage, .stage_time_active
stage_time_active,
stage_exhausted,
} = data.character
{
let mut new_stage_exhausted = *stage_exhausted;
let new_stage_time_active = stage_time_active
.checked_add(Duration::from_secs_f32(data.dt.0)) .checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or(Duration::default()); .unwrap_or(Duration::default());
@ -43,7 +50,7 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
return update; return update;
} }
while *stage < 3 { if self.stage < 3 {
if new_stage_time_active < Duration::from_millis(STAGE_DURATION / 3) { if new_stage_time_active < Duration::from_millis(STAGE_DURATION / 3) {
// Move player forward while in first third of each stage // Move player forward while in first third of each stage
handle_move(data, &mut update); handle_move(data, &mut update);
@ -54,7 +61,7 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
// TODO: deal damage // TODO: deal damage
} }
} }
}
update update
} }
}

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
comp::{CharacterAbility, CharacterState, EnergySource, ItemKind::Tool, StateUpdate, ToolData}, comp::{CharacterState, EnergySource, ItemKind::Tool, StateUpdate, ToolData},
event::LocalEvent, event::LocalEvent,
states::*, states::*,
sys::{character_behavior::JoinData, phys::GRAVITY}, sys::{character_behavior::JoinData, phys::GRAVITY},
@ -120,10 +120,10 @@ pub fn handle_wield(data: &JoinData, update: &mut StateUpdate) {
/// If a tool is equipped, goes into Equipping state, otherwise goes to Idle /// If a tool is equipped, goes into Equipping state, otherwise goes to Idle
pub fn attempt_wield(data: &JoinData, update: &mut StateUpdate) { pub fn attempt_wield(data: &JoinData, update: &mut StateUpdate) {
if let Some(Tool(tool)) = data.stats.equipment.main.as_ref().map(|i| i.kind) { if let Some(Tool(tool)) = data.stats.equipment.main.as_ref().map(|i| i.kind) {
update.character = CharacterState::Equipping { update.character = CharacterState::Equipping(equipping::Data {
tool, tool,
time_left: tool.equip_time(), time_left: tool.equip_time(),
}; });
} else { } else {
update.character = CharacterState::Idle {}; update.character = CharacterState::Idle {};
}; };

View File

@ -1,8 +1,17 @@
use super::utils::*; use super::utils::*;
use crate::{comp::StateUpdate, sys::character_behavior::JoinData}; use crate::{
comp::{StateUpdate, ToolData},
sys::character_behavior::{CharacterBehavior, JoinData},
};
use std::collections::VecDeque; use std::collections::VecDeque;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data {
/// The weapon being wielded
pub tool: ToolData,
}
pub fn behavior(data: &JoinData) -> StateUpdate { impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *data.character, character: *data.character,
pos: *data.pos, pos: *data.pos,
@ -25,3 +34,4 @@ pub fn behavior(data: &JoinData) -> StateUpdate {
update update
} }
}

View File

@ -172,18 +172,18 @@ impl<'a> System<'a> for Sys {
} }
let mut state_update = match j.character { let mut state_update = match j.character {
CharacterState::Idle { .. } => states::idle::behavior(&j), CharacterState::Idle => states::idle::Data::behavior(&states::idle::Data, &j),
CharacterState::Climb { .. } => states::climb::behavior(&j), CharacterState::Climb => states::climb::Data::behavior(&states::climb::Data, &j),
CharacterState::Glide { .. } => states::glide::behavior(&j), CharacterState::Glide => states::glide::Data::behavior(&states::glide::Data, &j),
CharacterState::Roll { .. } => states::roll::behavior(&j), CharacterState::Sit => states::sit::Data::behavior(&states::sit::Data, &j),
CharacterState::Wielding { .. } => states::wielding::behavior(&j), CharacterState::BasicBlock => states::basic_block::Data::behavior(&states::basic_block::Data, &j),
CharacterState::Equipping { .. } => states::equipping::behavior(&j), CharacterState::Roll (data) => data.behavior(&j),
CharacterState::BasicBlock { .. } => states::basic_block::behavior(&j), CharacterState::Wielding (data) => data.behavior(&j),
CharacterState::ChargeAttack { .. } => states::charge_attack::behavior(&j), CharacterState::Equipping (data) => data.behavior(&j),
CharacterState::Sit { .. } => states::sit::behavior(&j), CharacterState::ChargeAttack (data) => data.behavior(&j),
CharacterState::TripleStrike { .. } => states::triple_strike::behavior(&j), CharacterState::TripleStrike (data) => data.behavior(&j),
CharacterState::BasicAttack (state) => state.behavior(&j), CharacterState::BasicAttack (data) => data.behavior(&j),
CharacterState::TimedCombo(state) => state.behavior(&j), CharacterState::TimedCombo(data) => data.behavior(&j),
// Do not use default match. // Do not use default match.
// _ => StateUpdate { // _ => StateUpdate {