Added keyframes to all states that were lacking them.

This commit is contained in:
Sam 2020-10-16 21:29:14 -05:00
parent 5b19158da3
commit 63011241ea
13 changed files with 626 additions and 490 deletions

View File

@ -59,16 +59,16 @@ pub enum CharacterAbility {
BasicMelee { BasicMelee {
energy_cost: u32, energy_cost: u32,
buildup_duration: Duration, buildup_duration: Duration,
swing_duration: Duration,
recover_duration: Duration, recover_duration: Duration,
base_healthchange: i32, base_damage: u32,
knockback: f32, knockback: f32,
range: f32, range: f32,
max_angle: f32, max_angle: f32,
}, },
BasicRanged { BasicRanged {
energy_cost: u32, energy_cost: u32,
holdable: bool, buildup_duration: Duration,
prepare_duration: Duration,
recover_duration: Duration, recover_duration: Duration,
projectile: Projectile, projectile: Projectile,
projectile_body: Body, projectile_body: Body,
@ -91,7 +91,7 @@ pub enum CharacterAbility {
reps_remaining: u32, reps_remaining: u32,
}, },
Boost { Boost {
duration: Duration, movement_duration: Duration,
only_up: bool, only_up: bool,
}, },
DashMelee { DashMelee {
@ -169,7 +169,7 @@ pub enum CharacterAbility {
max_damage: u32, max_damage: u32,
initial_knockback: f32, initial_knockback: f32,
max_knockback: f32, max_knockback: f32,
prepare_duration: Duration, buildup_duration: Duration,
charge_duration: Duration, charge_duration: Duration,
recover_duration: Duration, recover_duration: Duration,
projectile_body: Body, projectile_body: Body,
@ -356,24 +356,29 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
match ability { match ability {
CharacterAbility::BasicMelee { CharacterAbility::BasicMelee {
buildup_duration, buildup_duration,
swing_duration,
recover_duration, recover_duration,
base_healthchange, base_damage,
knockback, knockback,
range, range,
max_angle, max_angle,
energy_cost: _, energy_cost: _,
} => CharacterState::BasicMelee(basic_melee::Data { } => CharacterState::BasicMelee(basic_melee::Data {
static_data: basic_melee::StaticData {
buildup_duration: *buildup_duration,
swing_duration: *swing_duration,
recover_duration: *recover_duration,
base_damage: *base_damage,
knockback: *knockback,
range: *range,
max_angle: *max_angle,
},
timer: Duration::default(),
stage_section: StageSection::Buildup,
exhausted: false, exhausted: false,
buildup_duration: *buildup_duration,
recover_duration: *recover_duration,
base_healthchange: *base_healthchange,
knockback: *knockback,
range: *range,
max_angle: *max_angle,
}), }),
CharacterAbility::BasicRanged { CharacterAbility::BasicRanged {
holdable, buildup_duration,
prepare_duration,
recover_duration, recover_duration,
projectile, projectile,
projectile_body, projectile_body,
@ -382,21 +387,29 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
projectile_speed, projectile_speed,
energy_cost: _, energy_cost: _,
} => CharacterState::BasicRanged(basic_ranged::Data { } => CharacterState::BasicRanged(basic_ranged::Data {
static_data: basic_ranged::StaticData {
buildup_duration: *buildup_duration,
recover_duration: *recover_duration,
projectile: projectile.clone(),
projectile_body: *projectile_body,
projectile_light: *projectile_light,
projectile_gravity: *projectile_gravity,
projectile_speed: *projectile_speed,
ability_key: key,
},
timer: Duration::default(),
stage_section: StageSection::Buildup,
exhausted: false, exhausted: false,
prepare_timer: Duration::default(),
holdable: *holdable,
prepare_duration: *prepare_duration,
recover_duration: *recover_duration,
projectile: projectile.clone(),
projectile_body: *projectile_body,
projectile_light: *projectile_light,
projectile_gravity: *projectile_gravity,
projectile_speed: *projectile_speed,
ability_key: key,
}), }),
CharacterAbility::Boost { duration, only_up } => CharacterState::Boost(boost::Data { CharacterAbility::Boost {
duration: *duration, movement_duration,
only_up: *only_up, only_up,
} => CharacterState::Boost(boost::Data {
static_data: boost::StaticData {
movement_duration: *movement_duration,
only_up: *only_up,
},
timer: Duration::default(),
}), }),
CharacterAbility::DashMelee { CharacterAbility::DashMelee {
energy_cost: _, energy_cost: _,
@ -438,7 +451,13 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
}), }),
CharacterAbility::BasicBlock => CharacterState::BasicBlock, CharacterAbility::BasicBlock => CharacterState::BasicBlock,
CharacterAbility::Roll => CharacterState::Roll(roll::Data { CharacterAbility::Roll => CharacterState::Roll(roll::Data {
remaining_duration: Duration::from_millis(500), static_data: roll::StaticData {
buildup_duration: Duration::from_millis(100),
movement_duration: Duration::from_millis(300),
recover_duration: Duration::from_millis(100),
},
timer: Duration::default(),
stage_section: StageSection::Buildup,
was_wielded: false, // false by default. utils might set it to true was_wielded: false, // false by default. utils might set it to true
}), }),
CharacterAbility::ComboMelee { CharacterAbility::ComboMelee {
@ -566,7 +585,7 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
max_damage, max_damage,
initial_knockback, initial_knockback,
max_knockback, max_knockback,
prepare_duration, buildup_duration,
charge_duration, charge_duration,
recover_duration, recover_duration,
projectile_body, projectile_body,
@ -575,21 +594,24 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
initial_projectile_speed, initial_projectile_speed,
max_projectile_speed, max_projectile_speed,
} => CharacterState::ChargedRanged(charged_ranged::Data { } => CharacterState::ChargedRanged(charged_ranged::Data {
static_data: charged_ranged::StaticData {
buildup_duration: *buildup_duration,
charge_duration: *charge_duration,
recover_duration: *recover_duration,
energy_drain: *energy_drain,
initial_damage: *initial_damage,
max_damage: *max_damage,
initial_knockback: *initial_knockback,
max_knockback: *max_knockback,
projectile_body: *projectile_body,
projectile_light: *projectile_light,
projectile_gravity: *projectile_gravity,
initial_projectile_speed: *initial_projectile_speed,
max_projectile_speed: *max_projectile_speed,
},
timer: Duration::default(),
stage_section: StageSection::Buildup,
exhausted: false, exhausted: false,
energy_drain: *energy_drain,
initial_damage: *initial_damage,
max_damage: *max_damage,
initial_knockback: *initial_knockback,
max_knockback: *max_knockback,
prepare_duration: *prepare_duration,
charge_duration: *charge_duration,
charge_timer: Duration::default(),
recover_duration: *recover_duration,
projectile_body: *projectile_body,
projectile_light: *projectile_light,
projectile_gravity: *projectile_gravity,
initial_projectile_speed: *initial_projectile_speed,
max_projectile_speed: *max_projectile_speed,
}), }),
CharacterAbility::RepeaterRanged { CharacterAbility::RepeaterRanged {
energy_cost: _, energy_cost: _,

View File

@ -206,9 +206,10 @@ impl Tool {
Axe(_) => vec![ Axe(_) => vec![
BasicMelee { BasicMelee {
energy_cost: 0, energy_cost: 0,
buildup_duration: Duration::from_millis(700), buildup_duration: Duration::from_millis(600),
swing_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(300), recover_duration: Duration::from_millis(300),
base_healthchange: (-120.0 * self.base_power()) as i32, base_damage: (120.0 * self.base_power()) as u32,
knockback: 0.0, knockback: 0.0,
range: 3.5, range: 3.5,
max_angle: 20.0, max_angle: 20.0,
@ -244,9 +245,10 @@ impl Tool {
Hammer(_) => vec![ Hammer(_) => vec![
BasicMelee { BasicMelee {
energy_cost: 0, energy_cost: 0,
buildup_duration: Duration::from_millis(700), buildup_duration: Duration::from_millis(600),
swing_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(300), recover_duration: Duration::from_millis(300),
base_healthchange: (-120.0 * self.base_power()) as i32, base_damage: (120.0 * self.base_power()) as u32,
knockback: 0.0, knockback: 0.0,
range: 3.5, range: 3.5,
max_angle: 20.0, max_angle: 20.0,
@ -280,9 +282,10 @@ impl Tool {
], ],
Farming(_) => vec![BasicMelee { Farming(_) => vec![BasicMelee {
energy_cost: 1, energy_cost: 1,
buildup_duration: Duration::from_millis(700), buildup_duration: Duration::from_millis(600),
swing_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(150), recover_duration: Duration::from_millis(150),
base_healthchange: (-50.0 * self.base_power()) as i32, base_damage: (50.0 * self.base_power()) as u32,
knockback: 0.0, knockback: 0.0,
range: 3.5, range: 3.5,
max_angle: 20.0, max_angle: 20.0,
@ -290,8 +293,7 @@ impl Tool {
Bow(_) => vec![ Bow(_) => vec![
BasicRanged { BasicRanged {
energy_cost: 0, energy_cost: 0,
holdable: true, buildup_duration: Duration::from_millis(100),
prepare_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(400), recover_duration: Duration::from_millis(400),
projectile: Projectile { projectile: Projectile {
hit_solid: vec![projectile::Effect::Stick], hit_solid: vec![projectile::Effect::Stick],
@ -317,7 +319,7 @@ impl Tool {
max_damage: (200.0 * self.base_power()) as u32, max_damage: (200.0 * self.base_power()) as u32,
initial_knockback: 10.0, initial_knockback: 10.0,
max_knockback: 20.0, max_knockback: 20.0,
prepare_duration: Duration::from_millis(100), buildup_duration: Duration::from_millis(100),
charge_duration: Duration::from_millis(1500), charge_duration: Duration::from_millis(1500),
recover_duration: Duration::from_millis(500), recover_duration: Duration::from_millis(500),
projectile_body: Body::Object(object::Body::MultiArrow), projectile_body: Body::Object(object::Body::MultiArrow),
@ -355,8 +357,9 @@ impl Tool {
Dagger(_) => vec![BasicMelee { Dagger(_) => vec![BasicMelee {
energy_cost: 0, energy_cost: 0,
buildup_duration: Duration::from_millis(100), buildup_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(400), swing_duration: Duration::from_millis(100),
base_healthchange: (-50.0 * self.base_power()) as i32, recover_duration: Duration::from_millis(300),
base_damage: (50.0 * self.base_power()) as u32,
knockback: 0.0, knockback: 0.0,
range: 3.5, range: 3.5,
max_angle: 20.0, max_angle: 20.0,
@ -378,8 +381,7 @@ impl Tool {
}, },
BasicRanged { BasicRanged {
energy_cost: 800, energy_cost: 800,
holdable: true, buildup_duration: Duration::from_millis(800),
prepare_duration: Duration::from_millis(800),
recover_duration: Duration::from_millis(50), recover_duration: Duration::from_millis(50),
projectile: Projectile { projectile: Projectile {
hit_solid: vec![ hit_solid: vec![
@ -422,8 +424,7 @@ impl Tool {
Staff(_) => vec![ Staff(_) => vec![
BasicRanged { BasicRanged {
energy_cost: 0, energy_cost: 0,
holdable: false, buildup_duration: Duration::from_millis(500),
prepare_duration: Duration::from_millis(500),
recover_duration: Duration::from_millis(350), recover_duration: Duration::from_millis(350),
projectile: Projectile { projectile: Projectile {
hit_solid: vec![ hit_solid: vec![
@ -495,8 +496,9 @@ impl Tool {
BasicMelee { BasicMelee {
energy_cost: 0, energy_cost: 0,
buildup_duration: Duration::from_millis(100), buildup_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(400), swing_duration: Duration::from_millis(100),
base_healthchange: (-40.0 * self.base_power()) as i32, recover_duration: Duration::from_millis(300),
base_damage: (40.0 * self.base_power()) as u32,
knockback: 0.0, knockback: 0.0,
range: 3.0, range: 3.0,
max_angle: 120.0, max_angle: 120.0,
@ -508,10 +510,11 @@ impl Tool {
vec![ vec![
BasicMelee { BasicMelee {
energy_cost: 0, energy_cost: 0,
buildup_duration: Duration::from_millis(500), buildup_duration: Duration::from_millis(400),
swing_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(250), recover_duration: Duration::from_millis(250),
knockback: 25.0, knockback: 25.0,
base_healthchange: -200, base_damage: 200,
range: 5.0, range: 5.0,
max_angle: 120.0, max_angle: 120.0,
}, },
@ -533,10 +536,11 @@ impl Tool {
} else if kind == "BeastClaws" { } else if kind == "BeastClaws" {
vec![BasicMelee { vec![BasicMelee {
energy_cost: 0, energy_cost: 0,
buildup_duration: Duration::from_millis(500), buildup_duration: Duration::from_millis(250),
swing_duration: Duration::from_millis(250),
recover_duration: Duration::from_millis(250), recover_duration: Duration::from_millis(250),
knockback: 25.0, knockback: 25.0,
base_healthchange: -200, base_damage: 200,
range: 5.0, range: 5.0,
max_angle: 120.0, max_angle: 120.0,
}] }]
@ -544,58 +548,50 @@ impl Tool {
vec![BasicMelee { vec![BasicMelee {
energy_cost: 0, energy_cost: 0,
buildup_duration: Duration::from_millis(100), buildup_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(300), swing_duration: Duration::from_millis(100),
base_healthchange: -10, recover_duration: Duration::from_millis(200),
base_damage: 10,
knockback: 0.0, knockback: 0.0,
range: 1.0, range: 1.0,
max_angle: 30.0, max_angle: 30.0,
}] }]
} }
}, },
Debug(kind) => { Debug(_) => vec![
if kind == "Boost" { CharacterAbility::Boost {
vec![ movement_duration: Duration::from_millis(50),
CharacterAbility::Boost { only_up: false,
duration: Duration::from_millis(50), },
only_up: false, CharacterAbility::Boost {
}, movement_duration: Duration::from_millis(50),
CharacterAbility::Boost { only_up: true,
duration: Duration::from_millis(50), },
only_up: true, BasicRanged {
}, energy_cost: 0,
BasicRanged { buildup_duration: Duration::from_millis(0),
energy_cost: 0, recover_duration: Duration::from_millis(10),
holdable: false, projectile: Projectile {
prepare_duration: Duration::from_millis(0), hit_solid: vec![projectile::Effect::Stick],
recover_duration: Duration::from_millis(10), hit_entity: vec![projectile::Effect::Stick, projectile::Effect::Possess],
projectile: Projectile { time_left: Duration::from_secs(10),
hit_solid: vec![projectile::Effect::Stick], owner: None,
hit_entity: vec![ ignore_group: false,
projectile::Effect::Stick, },
projectile::Effect::Possess, projectile_body: Body::Object(object::Body::ArrowSnake),
], projectile_light: Some(LightEmitter {
time_left: Duration::from_secs(10), col: (0.0, 1.0, 0.33).into(),
owner: None, ..Default::default()
ignore_group: false, }),
}, projectile_gravity: None,
projectile_body: Body::Object(object::Body::ArrowSnake), projectile_speed: 100.0,
projectile_light: Some(LightEmitter { },
col: (0.0, 1.0, 0.33).into(), ],
..Default::default()
}),
projectile_gravity: None,
projectile_speed: 100.0,
},
]
} else {
vec![]
}
},
Empty => vec![BasicMelee { Empty => vec![BasicMelee {
energy_cost: 0, energy_cost: 0,
buildup_duration: Duration::from_millis(0), buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(1000), swing_duration: Duration::from_millis(100),
base_healthchange: -20, recover_duration: Duration::from_millis(900),
base_damage: 20,
knockback: 0.0, knockback: 0.0,
range: 3.5, range: 3.5,
max_angle: 15.0, max_angle: 15.0,

View File

@ -163,8 +163,9 @@ impl LoadoutBuilder {
ability1: Some(CharacterAbility::BasicMelee { ability1: Some(CharacterAbility::BasicMelee {
energy_cost: 0, energy_cost: 0,
buildup_duration: Duration::from_millis(0), buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(400), swing_duration: Duration::from_millis(100),
base_healthchange: -40, recover_duration: Duration::from_millis(300),
base_damage: 40,
knockback: 0.0, knockback: 0.0,
range: 3.5, range: 3.5,
max_angle: 15.0, max_angle: 15.0,
@ -343,9 +344,10 @@ impl LoadoutBuilder {
item: Item::new_from_asset_expect("common.items.weapons.empty.empty"), item: Item::new_from_asset_expect("common.items.weapons.empty.empty"),
ability1: Some(CharacterAbility::BasicMelee { ability1: Some(CharacterAbility::BasicMelee {
energy_cost: 10, energy_cost: 10,
buildup_duration: Duration::from_millis(600), buildup_duration: Duration::from_millis(500),
swing_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(100), recover_duration: Duration::from_millis(100),
base_healthchange: -(body.base_dmg() as i32), base_damage: body.base_dmg(),
knockback: 0.0, knockback: 0.0,
range: body.base_range(), range: body.base_range(),
max_angle: 20.0, max_angle: 20.0,

View File

@ -6,20 +6,34 @@ use crate::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
/// Separated out to condense update portions of character state
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data { pub struct StaticData {
/// 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 is swinging for
pub swing_duration: Duration,
/// How long the state has until exiting /// How long the state has until exiting
pub recover_duration: Duration, pub recover_duration: Duration,
/// Base damage (negative) or healing (positive) /// Base damage
pub base_healthchange: i32, pub base_damage: u32,
/// Knockback /// Knockback
pub knockback: f32, pub knockback: f32,
/// Max range /// Max range
pub range: f32, pub range: f32,
/// Max angle (45.0 will give you a 90.0 angle window) /// Max angle (45.0 will give you a 90.0 angle window)
pub max_angle: f32, pub max_angle: f32,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data {
/// Struct containing data that does not change over the course of the
/// character state
pub static_data: StaticData,
/// Timer for each stage
pub timer: Duration,
/// What section the character stage is in
pub stage_section: StageSection,
/// Whether the attack can deal more damage /// Whether the attack can deal more damage
pub exhausted: bool, pub exhausted: bool,
} }
@ -31,65 +45,94 @@ impl CharacterBehavior for Data {
handle_move(data, &mut update, 0.7); handle_move(data, &mut update, 0.7);
handle_jump(data, &mut update); handle_jump(data, &mut update);
if self.buildup_duration != Duration::default() { match self.stage_section {
// Build up StageSection::Buildup => {
update.character = CharacterState::BasicMelee(Data { if self.timer < self.static_data.buildup_duration {
buildup_duration: self // Build up
.buildup_duration update.character = CharacterState::BasicMelee(Data {
.checked_sub(Duration::from_secs_f32(data.dt.0)) static_data: self.static_data,
.unwrap_or_default(), timer: self
recover_duration: self.recover_duration, .timer
base_healthchange: self.base_healthchange, .checked_add(Duration::from_secs_f32(data.dt.0))
knockback: self.knockback, .unwrap_or_default(),
range: self.range, stage_section: self.stage_section,
max_angle: self.max_angle, exhausted: self.exhausted,
exhausted: false, });
}); } else {
} else if !self.exhausted { // Transitions to swing section of stage
let (damage, heal) = if self.base_healthchange > 0 { update.character = CharacterState::BasicMelee(Data {
(0, self.base_healthchange as u32) static_data: self.static_data,
} else { timer: Duration::default(),
((-self.base_healthchange) as u32, 0) stage_section: StageSection::Swing,
}; exhausted: self.exhausted,
// Hit attempt });
data.updater.insert(data.entity, Attacking { }
base_damage: damage, },
base_heal: heal, StageSection::Swing => {
range: self.range, if !self.exhausted {
max_angle: self.max_angle.to_radians(), update.character = CharacterState::BasicMelee(Data {
applied: false, static_data: self.static_data,
hit_count: 0, timer: Duration::default(),
knockback: self.knockback, stage_section: self.stage_section,
}); exhausted: true,
});
update.character = CharacterState::BasicMelee(Data { // Hit attempt
buildup_duration: self.buildup_duration, data.updater.insert(data.entity, Attacking {
recover_duration: self.recover_duration, base_damage: self.static_data.base_damage,
base_healthchange: self.base_healthchange, base_heal: 0,
knockback: self.knockback, range: self.static_data.range,
range: self.range, max_angle: 180_f32.to_radians(),
max_angle: self.max_angle, applied: false,
exhausted: true, hit_count: 0,
}); knockback: self.static_data.knockback,
} else if self.recover_duration != Duration::default() { });
// Recovery } else if self.timer < self.static_data.swing_duration {
update.character = CharacterState::BasicMelee(Data { // Swings
buildup_duration: self.buildup_duration, update.character = CharacterState::BasicMelee(Data {
recover_duration: self static_data: self.static_data,
.recover_duration timer: self
.checked_sub(Duration::from_secs_f32(data.dt.0)) .timer
.unwrap_or_default(), .checked_add(Duration::from_secs_f32(data.dt.0))
base_healthchange: self.base_healthchange, .unwrap_or_default(),
knockback: self.knockback, stage_section: self.stage_section,
range: self.range, exhausted: self.exhausted,
max_angle: self.max_angle, });
exhausted: true, } else {
}); // Transitions to recover section of stage
} else { update.character = CharacterState::BasicMelee(Data {
// Done static_data: self.static_data,
update.character = CharacterState::Wielding; timer: Duration::default(),
// Make sure attack component is removed stage_section: StageSection::Recover,
data.updater.remove::<Attacking>(data.entity); exhausted: self.exhausted,
});
}
},
StageSection::Recover => {
if self.timer < self.static_data.recover_duration {
// Recovery
update.character = CharacterState::BasicMelee(Data {
static_data: self.static_data,
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
stage_section: self.stage_section,
exhausted: self.exhausted,
});
} else {
// Done
update.character = CharacterState::Wielding;
// Make sure attack component is removed
data.updater.remove::<Attacking>(data.entity);
}
},
_ => {
// If it somehow ends up in an incorrect stage section
update.character = CharacterState::Wielding;
// Make sure attack component is removed
data.updater.remove::<Attacking>(data.entity);
},
} }
// Grant energy on successful hit // Grant energy on successful hit

View File

@ -7,27 +7,36 @@ use crate::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
/// Separated out to condense update portions of character state
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data { pub struct StaticData {
/// Can you hold the ability beyond the prepare duration /// How much buildup is required before the attack
pub holdable: bool, pub buildup_duration: Duration,
/// How long we have to prepare the weapon
pub prepare_duration: Duration,
/// How long we prepared the weapon already
pub prepare_timer: Duration,
/// How long the state has until exiting /// How long the state has until exiting
pub recover_duration: Duration, pub recover_duration: Duration,
/// Projectile variables
pub projectile: Projectile, pub projectile: Projectile,
pub projectile_body: Body, pub projectile_body: Body,
pub projectile_light: Option<LightEmitter>, pub projectile_light: Option<LightEmitter>,
pub projectile_gravity: Option<Gravity>, pub projectile_gravity: Option<Gravity>,
pub projectile_speed: f32, pub projectile_speed: f32,
/// Whether the attack fired already
pub exhausted: bool,
/// What key is used to press ability /// What key is used to press ability
pub ability_key: AbilityKey, pub ability_key: AbilityKey,
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data {
/// Struct containing data that does not change over the course of the
/// character state
pub static_data: StaticData,
/// Timer for each stage
pub timer: Duration,
/// What section the character stage is in
pub stage_section: StageSection,
/// Whether the attack fired already
pub exhausted: bool,
}
impl CharacterBehavior for Data { impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate { fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data); let mut update = StateUpdate::from(data);
@ -35,77 +44,70 @@ impl CharacterBehavior for Data {
handle_move(data, &mut update, 0.3); handle_move(data, &mut update, 0.3);
handle_jump(data, &mut update); handle_jump(data, &mut update);
if !self.exhausted match self.stage_section {
&& if self.holdable { StageSection::Buildup => {
ability_key_is_pressed(data, self.ability_key) if self.timer < self.static_data.buildup_duration {
|| self.prepare_timer < self.prepare_duration // Build up
} else { update.character = CharacterState::BasicRanged(Data {
self.prepare_timer < self.prepare_duration static_data: self.static_data.clone(),
} timer: self
{ .timer
// Prepare (draw the bow) .checked_add(Duration::from_secs_f32(data.dt.0))
update.character = CharacterState::BasicRanged(Data { .unwrap_or_default(),
prepare_timer: self.prepare_timer + Duration::from_secs_f32(data.dt.0), stage_section: self.stage_section,
holdable: self.holdable, exhausted: self.exhausted,
prepare_duration: self.prepare_duration, });
recover_duration: self.recover_duration, } else {
projectile: self.projectile.clone(), // Transitions to recover section of stage
projectile_body: self.projectile_body, update.character = CharacterState::BasicRanged(Data {
projectile_light: self.projectile_light, static_data: self.static_data.clone(),
projectile_gravity: self.projectile_gravity, timer: Duration::default(),
projectile_speed: self.projectile_speed, stage_section: StageSection::Recover,
exhausted: false, exhausted: self.exhausted,
ability_key: self.ability_key, });
}); }
} else if !self.exhausted { },
// Fire StageSection::Recover => {
let mut projectile = self.projectile.clone(); if !self.exhausted {
projectile.owner = Some(*data.uid); // Fire
update.server_events.push_front(ServerEvent::Shoot { let mut projectile = self.static_data.projectile.clone();
entity: data.entity, projectile.owner = Some(*data.uid);
dir: data.inputs.look_dir, update.server_events.push_front(ServerEvent::Shoot {
body: self.projectile_body, entity: data.entity,
projectile, dir: data.inputs.look_dir,
light: self.projectile_light, body: self.static_data.projectile_body,
gravity: self.projectile_gravity, projectile,
speed: self.projectile_speed, light: self.static_data.projectile_light,
}); gravity: self.static_data.projectile_gravity,
speed: self.static_data.projectile_speed,
});
update.character = CharacterState::BasicRanged(Data { update.character = CharacterState::BasicRanged(Data {
prepare_timer: self.prepare_timer, static_data: self.static_data.clone(),
holdable: self.holdable, timer: self.timer,
prepare_duration: self.prepare_duration, stage_section: self.stage_section,
recover_duration: self.recover_duration, exhausted: true,
projectile: self.projectile.clone(), });
projectile_body: self.projectile_body, } else if self.timer < self.static_data.recover_duration {
projectile_light: self.projectile_light, // Recovers
projectile_gravity: self.projectile_gravity, update.character = CharacterState::BasicRanged(Data {
projectile_speed: self.projectile_speed, static_data: self.static_data.clone(),
exhausted: true, timer: self
ability_key: self.ability_key, .timer
}); .checked_add(Duration::from_secs_f32(data.dt.0))
} else if self.recover_duration != Duration::default() { .unwrap_or_default(),
// Recovery stage_section: self.stage_section,
update.character = CharacterState::BasicRanged(Data { exhausted: self.exhausted,
prepare_timer: self.prepare_timer, });
holdable: self.holdable, } else {
prepare_duration: self.prepare_duration, // Done
recover_duration: self update.character = CharacterState::Wielding;
.recover_duration }
.checked_sub(Duration::from_secs_f32(data.dt.0)) },
.unwrap_or_default(), _ => {
projectile: self.projectile.clone(), // If it somehow ends up in an incorrect stage section
projectile_body: self.projectile_body, update.character = CharacterState::Wielding;
projectile_light: self.projectile_light, },
projectile_gravity: self.projectile_gravity,
projectile_speed: self.projectile_speed,
exhausted: true,
ability_key: self.ability_key,
});
return update;
} else {
// Done
update.character = CharacterState::Wielding;
} }
update update

View File

@ -1,16 +1,25 @@
use crate::{ use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate}, comp::{CharacterState, StateUpdate},
states::utils::*, states::utils::*,
sys::character_behavior::{CharacterBehavior, JoinData}, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
/// Separated out to condense update portions of character state
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StaticData {
pub movement_duration: Duration,
pub only_up: bool,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data { pub struct Data {
/// How long the state has until exiting /// Struct containing data that does not change over the course of the
pub duration: Duration, /// character state
pub only_up: bool, pub static_data: StaticData,
/// Timer for each stage
pub timer: Duration,
} }
impl CharacterBehavior for Data { impl CharacterBehavior for Data {
@ -19,34 +28,25 @@ impl CharacterBehavior for Data {
handle_move(data, &mut update, 1.0); handle_move(data, &mut update, 1.0);
// Still going if self.timer < self.static_data.movement_duration {
if self.duration != Duration::default() { // Movement
if self.only_up { if self.static_data.only_up {
update.vel.0.z += 500.0 * data.dt.0; update.vel.0.z += 500.0 * data.dt.0;
} else { } else {
update.vel.0 += *data.inputs.look_dir * 500.0 * data.dt.0; update.vel.0 += *data.inputs.look_dir * 500.0 * data.dt.0;
} }
update.character = CharacterState::Boost(Data { update.character = CharacterState::Boost(Data {
duration: self static_data: self.static_data,
.duration timer: self
.checked_sub(Duration::from_secs_f32(data.dt.0)) .timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(), .unwrap_or_default(),
only_up: self.only_up,
}); });
} } else {
// Done // Done
else {
update.character = CharacterState::Wielding; update.character = CharacterState::Wielding;
} }
// Grant energy on successful hit
if let Some(attack) = data.attacking {
if attack.applied && attack.hit_count > 0 {
data.updater.remove::<Attacking>(data.entity);
update.energy.change_by(100, EnergySource::HitEnemy);
}
}
update update
} }
} }

View File

@ -10,10 +10,15 @@ use crate::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] /// Separated out to condense update portions of character state
pub struct Data { #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
/// Whether the attack fired already pub struct StaticData {
pub exhausted: bool, /// How long the weapon needs to be prepared for
pub buildup_duration: Duration,
/// How long it takes to charge the weapon to max damage and knockback
pub charge_duration: Duration,
/// How long the state has until exiting
pub recover_duration: Duration,
/// How much energy is drained per second when charging /// How much energy is drained per second when charging
pub energy_drain: u32, pub energy_drain: u32,
/// How much damage is dealt with no charge /// How much damage is dealt with no charge
@ -24,14 +29,6 @@ pub struct Data {
pub initial_knockback: f32, pub initial_knockback: f32,
/// How much knockback there is at max charge /// How much knockback there is at max charge
pub max_knockback: f32, pub max_knockback: f32,
/// How long the weapon needs to be prepared for
pub prepare_duration: Duration,
/// How long it takes to charge the weapon to max damage and knockback
pub charge_duration: Duration,
/// How long the state has been charging
pub charge_timer: Duration,
/// How long the state has until exiting
pub recover_duration: Duration,
/// Projectile information /// Projectile information
pub projectile_body: Body, pub projectile_body: Body,
pub projectile_light: Option<LightEmitter>, pub projectile_light: Option<LightEmitter>,
@ -40,6 +37,19 @@ pub struct Data {
pub max_projectile_speed: f32, pub max_projectile_speed: f32,
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data {
/// Struct containing data that does not change over the course of the
/// character state
pub static_data: StaticData,
/// Timer for each stage
pub timer: Duration,
/// What section the character stage is in
pub stage_section: StageSection,
/// Whether the attack fired already
pub exhausted: bool,
}
impl CharacterBehavior for Data { impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate { fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data); let mut update = StateUpdate::from(data);
@ -47,160 +57,133 @@ impl CharacterBehavior for Data {
handle_move(data, &mut update, 0.3); handle_move(data, &mut update, 0.3);
handle_jump(data, &mut update); handle_jump(data, &mut update);
if self.prepare_duration != Duration::default() { match self.stage_section {
// Prepare (draw the bow) StageSection::Buildup => {
update.character = CharacterState::ChargedRanged(Data { if self.timer < self.static_data.buildup_duration {
exhausted: self.exhausted, // Build up
energy_drain: self.energy_drain, update.character = CharacterState::ChargedRanged(Data {
initial_damage: self.initial_damage, static_data: self.static_data,
max_damage: self.max_damage, timer: self
initial_knockback: self.initial_knockback, .timer
max_knockback: self.max_knockback, .checked_add(Duration::from_secs_f32(data.dt.0))
prepare_duration: self .unwrap_or_default(),
.prepare_duration stage_section: self.stage_section,
.checked_sub(Duration::from_secs_f32(data.dt.0)) exhausted: self.exhausted,
.unwrap_or_default(), });
charge_duration: self.charge_duration, } else {
charge_timer: self.charge_timer, // Transitions to swing section of stage
recover_duration: self.recover_duration, update.character = CharacterState::ChargedRanged(Data {
projectile_body: self.projectile_body, static_data: self.static_data,
projectile_light: self.projectile_light, timer: Duration::default(),
projectile_gravity: self.projectile_gravity, stage_section: StageSection::Charge,
initial_projectile_speed: self.initial_projectile_speed, exhausted: self.exhausted,
max_projectile_speed: self.max_projectile_speed, });
}); }
} else if data.inputs.secondary.is_pressed() },
&& self.charge_timer < self.charge_duration StageSection::Charge => {
&& update.energy.current() > 0 if !data.inputs.secondary.is_pressed() && !self.exhausted {
{ let charge_frac = (self.timer.as_secs_f32()
// Charge the bow / self.static_data.charge_duration.as_secs_f32())
update.character = CharacterState::ChargedRanged(Data { .min(1.0);
exhausted: self.exhausted, let damage = self.static_data.initial_damage as f32
energy_drain: self.energy_drain, + (charge_frac
initial_damage: self.initial_damage, * (self.static_data.max_damage - self.static_data.initial_damage)
max_damage: self.max_damage, as f32);
initial_knockback: self.initial_knockback, let knockback = self.static_data.initial_knockback as f32
max_knockback: self.max_knockback, + (charge_frac
prepare_duration: self.prepare_duration, * (self.static_data.max_knockback - self.static_data.initial_knockback)
charge_timer: self as f32);
.charge_timer // Fire
.checked_add(Duration::from_secs_f32(data.dt.0)) let mut projectile = Projectile {
.unwrap_or_default(), hit_solid: vec![projectile::Effect::Stick],
charge_duration: self.charge_duration, hit_entity: vec![
recover_duration: self.recover_duration, projectile::Effect::Damage(-damage as i32),
projectile_body: self.projectile_body, projectile::Effect::Knockback(knockback),
projectile_light: self.projectile_light, projectile::Effect::Vanish,
projectile_gravity: self.projectile_gravity, ],
initial_projectile_speed: self.initial_projectile_speed, time_left: Duration::from_secs(15),
max_projectile_speed: self.max_projectile_speed, owner: None,
}); ignore_group: true,
};
projectile.owner = Some(*data.uid);
update.server_events.push_front(ServerEvent::Shoot {
entity: data.entity,
dir: data.inputs.look_dir,
body: self.static_data.projectile_body,
projectile,
light: self.static_data.projectile_light,
gravity: self.static_data.projectile_gravity,
speed: self.static_data.initial_projectile_speed
+ charge_frac
* (self.static_data.max_projectile_speed
- self.static_data.initial_projectile_speed),
});
// Consumes energy if there's enough left and RMB is held down update.character = CharacterState::ChargedRanged(Data {
update.energy.change_by( static_data: self.static_data,
-(self.energy_drain as f32 * data.dt.0) as i32, timer: Duration::default(),
EnergySource::Ability, stage_section: StageSection::Recover,
); exhausted: true,
} else if data.inputs.secondary.is_pressed() { });
// Charge the bow } else if self.timer < self.static_data.charge_duration
update.character = CharacterState::ChargedRanged(Data { && data.inputs.secondary.is_pressed()
exhausted: self.exhausted, {
energy_drain: self.energy_drain, // Charges
initial_damage: self.initial_damage, update.character = CharacterState::ChargedRanged(Data {
max_damage: self.max_damage, static_data: self.static_data,
initial_knockback: self.initial_knockback, timer: self
max_knockback: self.max_knockback, .timer
prepare_duration: self.prepare_duration, .checked_add(Duration::from_secs_f32(data.dt.0))
charge_timer: self.charge_timer, .unwrap_or_default(),
charge_duration: self.charge_duration, stage_section: self.stage_section,
recover_duration: self.recover_duration, exhausted: self.exhausted,
projectile_body: self.projectile_body, });
projectile_light: self.projectile_light,
projectile_gravity: self.projectile_gravity,
initial_projectile_speed: self.initial_projectile_speed,
max_projectile_speed: self.max_projectile_speed,
});
// Consumes energy if there's enough left and RMB is held down // Consumes energy if there's enough left and RMB is held down
update.energy.change_by( update.energy.change_by(
-(self.energy_drain as f32 * data.dt.0 / 5.0) as i32, -(self.static_data.energy_drain as f32 * data.dt.0) as i32,
EnergySource::Ability, EnergySource::Ability,
); );
} else if !self.exhausted { } else if data.inputs.secondary.is_pressed() {
let charge_amount = // Holds charge
(self.charge_timer.as_secs_f32() / self.charge_duration.as_secs_f32()).min(1.0); update.character = CharacterState::ChargedRanged(Data {
// Fire static_data: self.static_data,
let mut projectile = Projectile { timer: self
hit_solid: vec![projectile::Effect::Stick], .timer
hit_entity: vec![ .checked_add(Duration::from_secs_f32(data.dt.0))
projectile::Effect::Damage( .unwrap_or_default(),
-(self.initial_damage as i32 stage_section: self.stage_section,
+ (charge_amount * (self.max_damage - self.initial_damage) as f32) exhausted: self.exhausted,
as i32), });
),
projectile::Effect::Knockback(
self.initial_knockback
+ charge_amount * (self.max_knockback - self.initial_knockback),
),
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(15),
owner: None,
ignore_group: true,
};
projectile.owner = Some(*data.uid);
update.server_events.push_front(ServerEvent::Shoot {
entity: data.entity,
dir: data.inputs.look_dir,
body: self.projectile_body,
projectile,
light: self.projectile_light,
gravity: self.projectile_gravity,
speed: self.initial_projectile_speed
+ charge_amount * (self.max_projectile_speed - self.initial_projectile_speed),
});
update.character = CharacterState::ChargedRanged(Data { // Consumes energy if there's enough left and RMB is held down
exhausted: true, update.energy.change_by(
energy_drain: self.energy_drain, -(self.static_data.energy_drain as f32 * data.dt.0 / 5.0) as i32,
initial_damage: self.initial_damage, EnergySource::Ability,
max_damage: self.max_damage, );
initial_knockback: self.initial_knockback, }
max_knockback: self.max_knockback, },
prepare_duration: self.prepare_duration, StageSection::Recover => {
charge_timer: self.charge_timer, if self.timer < self.static_data.recover_duration {
charge_duration: self.charge_duration, // Recovers
recover_duration: self.recover_duration, update.character = CharacterState::ChargedRanged(Data {
projectile_body: self.projectile_body, static_data: self.static_data,
projectile_light: self.projectile_light, timer: self
projectile_gravity: self.projectile_gravity, .timer
initial_projectile_speed: self.initial_projectile_speed, .checked_add(Duration::from_secs_f32(data.dt.0))
max_projectile_speed: self.max_projectile_speed, .unwrap_or_default(),
}); stage_section: self.stage_section,
} else if self.recover_duration != Duration::default() { exhausted: self.exhausted,
// Recovery });
update.character = CharacterState::ChargedRanged(Data { } else {
exhausted: self.exhausted, // Done
energy_drain: self.energy_drain, update.character = CharacterState::Wielding;
initial_damage: self.initial_damage, }
max_damage: self.max_damage, },
initial_knockback: self.initial_knockback, _ => {
max_knockback: self.max_knockback, // If it somehow ends up in an incorrect stage section
prepare_duration: self.prepare_duration, update.character = CharacterState::Wielding;
charge_timer: self.charge_timer, },
charge_duration: self.charge_duration,
recover_duration: self
.recover_duration
.checked_sub(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
projectile_body: self.projectile_body,
projectile_light: self.projectile_light,
projectile_gravity: self.projectile_gravity,
initial_projectile_speed: self.initial_projectile_speed,
max_projectile_speed: self.max_projectile_speed,
});
} else {
// Done
update.character = CharacterState::Wielding;
} }
update update

View File

@ -6,10 +6,20 @@ use crate::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] /// Separated out to condense update portions of character state
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StaticData {
/// Time required to draw weapon
pub buildup_duration: Duration,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data { pub struct Data {
/// Time left before next state /// Struct containing data that does not change over the course of the
pub time_left: Duration, /// character state
pub static_data: StaticData,
/// Timer for each stage
pub timer: Duration,
} }
impl CharacterBehavior for Data { impl CharacterBehavior for Data {
@ -19,18 +29,18 @@ impl CharacterBehavior for Data {
handle_move(&data, &mut update, 1.0); handle_move(&data, &mut update, 1.0);
handle_jump(&data, &mut update); handle_jump(&data, &mut update);
if self.time_left == Duration::default() { if self.timer < self.static_data.buildup_duration {
// Wield delay has expired // Draw weapon
update.character = CharacterState::Wielding;
} else {
// Wield delay hasn't expired yet
// Update wield delay
update.character = CharacterState::Equipping(Data { update.character = CharacterState::Equipping(Data {
time_left: self static_data: self.static_data,
.time_left timer: self
.checked_sub(Duration::from_secs_f32(data.dt.0)) .timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(), .unwrap_or_default(),
}); });
} else {
// Done
update.character = CharacterState::Wielding;
} }
update update

View File

@ -1,5 +1,6 @@
use crate::{ use crate::{
comp::{CharacterState, StateUpdate}, comp::{CharacterState, StateUpdate},
states::utils::*,
sys::character_behavior::{CharacterBehavior, JoinData}, sys::character_behavior::{CharacterBehavior, JoinData},
util::Dir, util::Dir,
}; };
@ -8,10 +9,27 @@ use std::time::Duration;
use vek::Vec3; use vek::Vec3;
const ROLL_SPEED: f32 = 25.0; const ROLL_SPEED: f32 = 25.0;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
/// Separated out to condense update portions of character state
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StaticData {
/// How long until state should roll
pub buildup_duration: Duration,
/// How long state is rolling for
pub movement_duration: Duration,
/// How long it takes to recover from roll
pub recover_duration: Duration,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data { pub struct Data {
/// How long the state has until exiting /// Struct containing data that does not change over the course of the
pub remaining_duration: Duration, /// character state
pub static_data: StaticData,
/// Timer for each stage
pub timer: Duration,
/// What section the character stage is in
pub stage_section: StageSection,
/// Had weapon /// Had weapon
pub was_wielded: bool, pub was_wielded: bool,
} }
@ -31,23 +49,80 @@ impl CharacterBehavior for Data {
// Smooth orientation // Smooth orientation
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, update.vel.0.xy().into(), 9.0 * data.dt.0); update.ori.0 = Dir::slerp_to_vec3(update.ori.0, update.vel.0.xy().into(), 9.0 * data.dt.0);
if self.remaining_duration == Duration::default() { match self.stage_section {
// Roll duration has expired StageSection::Buildup => {
update.vel.0 *= 0.3; if self.timer < self.static_data.buildup_duration {
if self.was_wielded { // Build up
update.character = CharacterState::Wielding; update.character = CharacterState::Roll(Data {
} else { static_data: self.static_data,
update.character = CharacterState::Idle; timer: self
} .timer
} else { .checked_add(Duration::from_secs_f32(data.dt.0))
// Otherwise, tick down remaining_duration .unwrap_or_default(),
update.character = CharacterState::Roll(Data { stage_section: self.stage_section,
remaining_duration: self was_wielded: self.was_wielded,
.remaining_duration });
.checked_sub(Duration::from_secs_f32(data.dt.0)) } else {
.unwrap_or_default(), // Transitions to movement section of stage
was_wielded: self.was_wielded, update.character = CharacterState::Roll(Data {
}); static_data: self.static_data,
timer: Duration::default(),
stage_section: StageSection::Movement,
was_wielded: self.was_wielded,
});
}
},
StageSection::Movement => {
if self.timer < self.static_data.movement_duration {
// Movement
update.character = CharacterState::Roll(Data {
static_data: self.static_data,
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
stage_section: self.stage_section,
was_wielded: self.was_wielded,
});
} else {
// Transitions to recover section of stage
update.character = CharacterState::Roll(Data {
static_data: self.static_data,
timer: Duration::default(),
stage_section: StageSection::Recover,
was_wielded: self.was_wielded,
});
}
},
StageSection::Recover => {
if self.timer < self.static_data.recover_duration {
// Build up
update.character = CharacterState::Roll(Data {
static_data: self.static_data,
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
stage_section: self.stage_section,
was_wielded: self.was_wielded,
});
} else {
// Done
if self.was_wielded {
update.character = CharacterState::Wielding;
} else {
update.character = CharacterState::Idle;
}
}
},
_ => {
// If it somehow ends up in an incorrect stage section
if self.was_wielded {
update.character = CharacterState::Wielding;
} else {
update.character = CharacterState::Idle;
}
},
} }
update update

View File

@ -9,6 +9,7 @@ use crate::{
util::Dir, util::Dir,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration;
use vek::*; use vek::*;
pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0; pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
@ -161,7 +162,10 @@ pub fn handle_wield(data: &JoinData, update: &mut StateUpdate) {
pub fn attempt_wield(data: &JoinData, update: &mut StateUpdate) { pub fn attempt_wield(data: &JoinData, update: &mut StateUpdate) {
if let Some(ItemKind::Tool(tool)) = data.loadout.active_item.as_ref().map(|i| i.item.kind()) { if let Some(ItemKind::Tool(tool)) = data.loadout.active_item.as_ref().map(|i| i.item.kind()) {
update.character = CharacterState::Equipping(equipping::Data { update.character = CharacterState::Equipping(equipping::Data {
time_left: tool.equip_time(), static_data: equipping::StaticData {
buildup_duration: tool.equip_time(),
},
timer: Duration::default(),
}); });
} else { } else {
update.character = CharacterState::Idle; update.character = CharacterState::Idle;

View File

@ -79,7 +79,7 @@ impl State {
if let ItemKind::Tool(kind) = kind { if let ItemKind::Tool(kind) = kind {
match &kind.kind { match &kind.kind {
ToolKind::Staff(_) => true, ToolKind::Staff(_) => true,
ToolKind::Debug(kind) => kind == "Boost", ToolKind::Debug(_) => true,
ToolKind::Sword(_) => true, ToolKind::Sword(_) => true,
ToolKind::Hammer(_) => true, ToolKind::Hammer(_) => true,
ToolKind::Axe(_) => true, ToolKind::Axe(_) => true,

View File

@ -524,6 +524,14 @@ impl<'a> Widget for Skillbar<'a> {
.map(|i| i.item.kind()) .map(|i| i.item.kind())
.and_then(|kind| match kind { .and_then(|kind| match kind {
ItemKind::Tool(Tool { kind, .. }) => match kind { ItemKind::Tool(Tool { kind, .. }) => match kind {
ToolKind::Hammer(_) => Some((
"Smash of Doom",
"\nAn AOE attack with knockback. \nLeaps to position of \
cursor.",
)),
ToolKind::Axe(_) => {
Some(("Spin Leap", "\nA slashing running spin leap."))
},
ToolKind::Staff(_) => Some(( ToolKind::Staff(_) => Some((
"Firebomb", "Firebomb",
"\nWhirls a big fireball into the air. \nExplodes the ground \ "\nWhirls a big fireball into the air. \nExplodes the ground \
@ -533,14 +541,14 @@ impl<'a> Widget for Skillbar<'a> {
"Whirlwind", "Whirlwind",
"\nMove forward while spinning with \n your sword.", "\nMove forward while spinning with \n your sword.",
)), )),
ToolKind::Debug(kind) => match kind.as_ref() { ToolKind::Bow(_) => Some((
"Boost" => Some(( "Burst",
"Possessing Arrow", "\nLaunches a burst of arrows at the top \nof a running leap.",
"\nShoots a poisonous arrow.\nLets you control your \ )),
target.", ToolKind::Debug(_) => Some((
)), "Possessing Arrow",
_ => None, "\nShoots a poisonous arrow.\nLets you control your target.",
}, )),
_ => None, _ => None,
}, },
_ => None, _ => None,
@ -621,10 +629,7 @@ impl<'a> Widget for Skillbar<'a> {
ToolKind::Bow(_) => self.imgs.bow_m1, ToolKind::Bow(_) => self.imgs.bow_m1,
ToolKind::Sceptre(_) => self.imgs.heal_0, ToolKind::Sceptre(_) => self.imgs.heal_0,
ToolKind::Staff(_) => self.imgs.fireball, ToolKind::Staff(_) => self.imgs.fireball,
ToolKind::Debug(kind) => match kind.as_ref() { ToolKind::Debug(_) => self.imgs.flyingrod_m1,
"Boost" => self.imgs.flyingrod_m1,
_ => self.imgs.nothing,
},
_ => self.imgs.nothing, _ => self.imgs.nothing,
}, },
_ => self.imgs.nothing, _ => self.imgs.nothing,
@ -671,10 +676,7 @@ impl<'a> Widget for Skillbar<'a> {
Some(ToolKind::Bow(_)) => self.imgs.bow_m2, Some(ToolKind::Bow(_)) => self.imgs.bow_m2,
Some(ToolKind::Sceptre(_)) => self.imgs.heal_bomb, Some(ToolKind::Sceptre(_)) => self.imgs.heal_bomb,
Some(ToolKind::Staff(_)) => self.imgs.flamethrower, Some(ToolKind::Staff(_)) => self.imgs.flamethrower,
Some(ToolKind::Debug(kind)) => match kind.as_ref() { Some(ToolKind::Debug(_)) => self.imgs.flyingrod_m2,
"Boost" => self.imgs.flyingrod_m2,
_ => self.imgs.nothing,
},
_ => self.imgs.nothing, _ => self.imgs.nothing,
}) })
.w_h(36.0, 36.0) .w_h(36.0, 36.0)

View File

@ -116,10 +116,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
ToolKind::Hammer(_) => Some(HotbarImage::HammerLeap), ToolKind::Hammer(_) => Some(HotbarImage::HammerLeap),
ToolKind::Axe(_) => Some(HotbarImage::AxeLeapSlash), ToolKind::Axe(_) => Some(HotbarImage::AxeLeapSlash),
ToolKind::Bow(_) => Some(HotbarImage::BowJumpBurst), ToolKind::Bow(_) => Some(HotbarImage::BowJumpBurst),
ToolKind::Debug(kind) => match kind.as_ref() { ToolKind::Debug(_) => Some(HotbarImage::SnakeArrow),
"Boost" => Some(HotbarImage::SnakeArrow),
_ => None,
},
ToolKind::Sword(_) => Some(HotbarImage::SwordWhirlwind), ToolKind::Sword(_) => Some(HotbarImage::SwordWhirlwind),
_ => None, _ => None,
}, },