mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
starting stun anim
stagger anim, mirroring, bettern walk anim wielding with stuns/stagger Knockback fix Added Poise documentation/comments
This commit is contained in:
parent
0f244bf84b
commit
29732bb763
286
4
286
4
@ -1,286 +0,0 @@
|
||||
use crate::{
|
||||
comp::{Attacking, CharacterState, EnergyChange, EnergySource, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*,
|
||||
},
|
||||
Damage, DamageSource, GroupTarget, Knockback,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Stage<T> {
|
||||
/// Specifies which stage the combo attack is in
|
||||
pub stage: u32,
|
||||
/// Initial damage of stage
|
||||
pub base_damage: u32,
|
||||
/// Max damage of stage
|
||||
pub max_damage: u32,
|
||||
/// Damage scaling per combo
|
||||
pub damage_increase: u32,
|
||||
/// Initial poise damage of stage
|
||||
pub base_poise_damage: u32,
|
||||
/// Knockback of stage
|
||||
pub knockback: f32,
|
||||
/// Range of attack
|
||||
pub range: f32,
|
||||
/// Angle of attack
|
||||
pub angle: f32,
|
||||
/// Initial buildup duration of stage (how long until state can deal damage)
|
||||
pub base_buildup_duration: T,
|
||||
/// Duration of stage spent in swing (controls animation stuff, and can also
|
||||
/// be used to handle movement separately to buildup)
|
||||
pub base_swing_duration: T,
|
||||
/// Initial recover duration of stage (how long until character exits state)
|
||||
pub base_recover_duration: T,
|
||||
/// How much forward movement there is in the swing portion of the stage
|
||||
pub forward_movement: f32,
|
||||
}
|
||||
|
||||
impl Stage<u64> {
|
||||
pub fn to_duration(self) -> Stage<Duration> {
|
||||
Stage::<Duration> {
|
||||
stage: self.stage,
|
||||
base_damage: self.base_damage,
|
||||
max_damage: self.max_damage,
|
||||
damage_increase: self.damage_increase,
|
||||
base_poise_damage: self.base_poise_damage,
|
||||
knockback: self.knockback,
|
||||
range: self.range,
|
||||
angle: self.angle,
|
||||
base_buildup_duration: Duration::from_millis(self.base_buildup_duration),
|
||||
base_swing_duration: Duration::from_millis(self.base_swing_duration),
|
||||
base_recover_duration: Duration::from_millis(self.base_recover_duration),
|
||||
forward_movement: self.forward_movement,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adjusted_by_stats(mut self, power: f32, speed: f32) -> Self {
|
||||
self.base_damage = (self.base_damage as f32 * power) as u32;
|
||||
self.max_damage = (self.max_damage as f32 * power) as u32;
|
||||
self.damage_increase = (self.damage_increase as f32 * power) as u32;
|
||||
self.base_buildup_duration = (self.base_buildup_duration as f32 / speed) as u64;
|
||||
self.base_swing_duration = (self.base_swing_duration as f32 / speed) as u64;
|
||||
self.base_recover_duration = (self.base_recover_duration as f32 / speed) as u64;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
/// Separated out to condense update portions of character state
|
||||
pub struct StaticData {
|
||||
/// Indicates number of stages in combo
|
||||
pub num_stages: u32,
|
||||
/// Data for each stage
|
||||
pub stage_data: Vec<Stage<Duration>>,
|
||||
/// Initial energy gain per strike
|
||||
pub initial_energy_gain: u32,
|
||||
/// Max energy gain per strike
|
||||
pub max_energy_gain: u32,
|
||||
/// Energy gain increase per combo
|
||||
pub energy_increase: u32,
|
||||
/// (100% - speed_increase) is percentage speed increases from current to
|
||||
/// max when combo increases
|
||||
pub speed_increase: f32,
|
||||
/// (100% + max_speed_increase) is the max attack speed
|
||||
pub max_speed_increase: f32,
|
||||
/// Whether the state can be interrupted by other abilities
|
||||
pub is_interruptible: bool,
|
||||
/// What key is used to press ability
|
||||
pub ability_key: AbilityKey,
|
||||
}
|
||||
/// A sequence of attacks that can incrementally become faster and more
|
||||
/// damaging.
|
||||
#[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,
|
||||
/// Indicates what stage the combo is in
|
||||
pub stage: u32,
|
||||
/// Number of consecutive strikes
|
||||
pub combo: u32,
|
||||
/// Timer for each stage
|
||||
pub timer: Duration,
|
||||
/// Checks what section a stage is in
|
||||
pub stage_section: StageSection,
|
||||
/// Whether the state should go onto the next stage
|
||||
pub next_stage: bool,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_move(data, &mut update, 0.3);
|
||||
if !ability_key_is_pressed(data, self.static_data.ability_key) {
|
||||
handle_interrupt(data, &mut update, self.static_data.is_interruptible);
|
||||
if let CharacterState::Roll(roll) = &mut update.character {
|
||||
roll.was_combo = Some((self.stage, self.combo));
|
||||
}
|
||||
match update.character {
|
||||
CharacterState::ComboMelee(_) => {},
|
||||
_ => {
|
||||
return update;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let stage_index = (self.stage - 1) as usize;
|
||||
|
||||
let speed_modifer = 1.0
|
||||
+ self.static_data.max_speed_increase
|
||||
* (1.0 - self.static_data.speed_increase.powi(self.combo as i32));
|
||||
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
if self.timer < self.static_data.stage_data[stage_index].base_buildup_duration {
|
||||
// Build up
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0 * speed_modifer))
|
||||
.unwrap_or_default(),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
// Transitions to swing section of stage
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Swing,
|
||||
..*self
|
||||
});
|
||||
|
||||
// Hit attempt
|
||||
let damage = self.static_data.stage_data[stage_index].max_damage.min(
|
||||
self.static_data.stage_data[stage_index].base_damage
|
||||
+ self.combo / self.static_data.num_stages
|
||||
* self.static_data.stage_data[stage_index].damage_increase,
|
||||
);
|
||||
let poise_damage = self.static_data.stage_data[stage_index].base_poise_damage;
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
damages: vec![(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Melee,
|
||||
value: damage as f32,
|
||||
poise_damage: poise_damage as f32,
|
||||
})],
|
||||
range: self.static_data.stage_data[stage_index].range,
|
||||
max_angle: self.static_data.stage_data[stage_index].angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
knockback: Knockback::Away(
|
||||
self.static_data.stage_data[stage_index].knockback,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Swing => {
|
||||
if self.timer < self.static_data.stage_data[stage_index].base_swing_duration {
|
||||
// Forward movement
|
||||
handle_forced_movement(
|
||||
data,
|
||||
&mut update,
|
||||
ForcedMovement::Forward {
|
||||
strength: self.static_data.stage_data[stage_index].forward_movement,
|
||||
},
|
||||
0.3,
|
||||
);
|
||||
|
||||
// Swings
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0 * speed_modifer))
|
||||
.unwrap_or_default(),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
// Transitions to recover section of stage
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Recover,
|
||||
..*self
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Recover => {
|
||||
if self.timer < self.static_data.stage_data[stage_index].base_recover_duration {
|
||||
// Recovers
|
||||
if ability_key_is_pressed(data, self.static_data.ability_key) {
|
||||
// Checks if state will transition to next stage after recover
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0 * speed_modifer))
|
||||
.unwrap_or_default(),
|
||||
next_stage: true,
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0 * speed_modifer))
|
||||
.unwrap_or_default(),
|
||||
..*self
|
||||
});
|
||||
}
|
||||
} else if self.next_stage {
|
||||
// Transitions to buildup section of next stage
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
stage: (self.stage % self.static_data.num_stages) + 1,
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
next_stage: false,
|
||||
..*self
|
||||
});
|
||||
} 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
|
||||
if let Some(attack) = data.attacking {
|
||||
if attack.applied && attack.hit_count > 0 {
|
||||
let energy = self.static_data.max_energy_gain.min(
|
||||
self.static_data.initial_energy_gain
|
||||
+ self.combo * self.static_data.energy_increase,
|
||||
) as i32;
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
stage: self.stage,
|
||||
combo: self.combo + 1,
|
||||
timer: self.timer,
|
||||
stage_section: self.stage_section,
|
||||
next_stage: self.next_stage,
|
||||
});
|
||||
data.updater.remove::<Attacking>(data.entity);
|
||||
update.energy.change_by(EnergyChange {
|
||||
amount: energy,
|
||||
source: EnergySource::HitEnemy,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
}
|
@ -1,8 +1,4 @@
|
||||
use crate::{
|
||||
comp::{PoiseChange, PoiseSource},
|
||||
uid::Uid,
|
||||
Damage, GroupTarget,
|
||||
};
|
||||
use crate::{comp::PoiseChange, uid::Uid, Damage, GroupTarget};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, DerefFlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
|
@ -139,6 +139,8 @@ impl CharacterState {
|
||||
| CharacterState::RepeaterRanged(_)
|
||||
| CharacterState::Shockwave(_)
|
||||
| CharacterState::BasicBeam(_)
|
||||
| CharacterState::Stunned(_)
|
||||
| CharacterState::Staggered(_)
|
||||
| CharacterState::Wielding
|
||||
)
|
||||
}
|
||||
|
@ -4,20 +4,19 @@ use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use vek::*;
|
||||
|
||||
/// A change in the poise component. Stores the amount as a signed
|
||||
/// integer to allow for added or removed poise. Also has a field to
|
||||
/// label where the poise change came from.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct PoiseChange {
|
||||
/// Value of the change in poise
|
||||
pub amount: i32,
|
||||
/// Source of change in poise
|
||||
pub source: PoiseSource,
|
||||
}
|
||||
|
||||
impl PoiseChange {
|
||||
pub fn set_zero(self) -> Self {
|
||||
Self {
|
||||
amount: 0,
|
||||
source: self.source,
|
||||
}
|
||||
}
|
||||
|
||||
/// Alters poise damage as a result of armor poise damage reduction
|
||||
pub fn modify_poise_damage(self, loadout: Option<&Loadout>) -> PoiseChange {
|
||||
let mut poise_damage = self.amount as f32;
|
||||
match self.source {
|
||||
@ -77,6 +76,7 @@ impl PoiseChange {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sources of poise change
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PoiseSource {
|
||||
LevelUp,
|
||||
@ -91,17 +91,20 @@ pub enum PoiseSource {
|
||||
Other,
|
||||
}
|
||||
|
||||
/// Poise component
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct Poise {
|
||||
/// Base poise amount for this entity
|
||||
base_max: u32,
|
||||
/// Poise of entity at any given moment
|
||||
current: u32,
|
||||
/// Maximum poise of entity at a given time
|
||||
maximum: u32,
|
||||
/// Knockback direction of last change, for use as an effect in sys/stats.rs
|
||||
knockback: Vec3<f32>,
|
||||
/// Last poise change, storing time since last change
|
||||
pub last_change: (f64, PoiseChange),
|
||||
pub is_interrupted: bool,
|
||||
pub is_stunned: bool,
|
||||
pub is_dazed: bool,
|
||||
pub is_knockeddown: bool,
|
||||
/// Rate of poise regeneration per tick. Starts at zero and accelerates.
|
||||
pub regen_rate: f32,
|
||||
}
|
||||
|
||||
@ -116,35 +119,41 @@ impl Default for Poise {
|
||||
amount: 0,
|
||||
source: PoiseSource::Revive,
|
||||
}),
|
||||
is_interrupted: false,
|
||||
is_stunned: false,
|
||||
is_dazed: false,
|
||||
is_knockeddown: false,
|
||||
regen_rate: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// States to define effects of a poise change
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub enum PoiseState {
|
||||
/// No effect applied
|
||||
Normal,
|
||||
/// Poise reset, and target briefly stunned
|
||||
Interrupted,
|
||||
/// Poise reset, target stunned and knocked back horizontally
|
||||
Stunned,
|
||||
/// Poise reset, target staggered
|
||||
Dazed,
|
||||
/// Poise reset, target staggered and knocked back further
|
||||
KnockedDown,
|
||||
}
|
||||
|
||||
impl Poise {
|
||||
/// Creates a new poise struct based on the body it is being assigned to
|
||||
pub fn new(body: Body) -> Self {
|
||||
let mut poise = Poise::default();
|
||||
poise.update_max_poise(Some(body));
|
||||
poise.set_to(poise.maximum(), PoiseSource::Revive);
|
||||
poise.update_base_max(Some(body));
|
||||
poise.set_maximum(poise.base_max);
|
||||
poise.set_to(poise.maximum, PoiseSource::Revive);
|
||||
|
||||
poise
|
||||
}
|
||||
|
||||
/// Returns knockback as a Vec3
|
||||
pub fn knockback(&self) -> Vec3<f32> { self.knockback }
|
||||
|
||||
/// Defines the poise states based on fraction of maximum poise
|
||||
pub fn poise_state(&self) -> PoiseState {
|
||||
if self.current >= 8 * self.maximum / 10 {
|
||||
PoiseState::Normal
|
||||
@ -159,10 +168,17 @@ impl Poise {
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the current poise value
|
||||
pub fn current(&self) -> u32 { self.current }
|
||||
|
||||
/// Gets the maximum poise value
|
||||
pub fn maximum(&self) -> u32 { self.maximum }
|
||||
|
||||
/// Gets the base_max value
|
||||
pub fn base_max(&self) -> u32 { self.base_max }
|
||||
|
||||
/// Sets the poise value to a provided value. First cuts off the value
|
||||
/// at the maximum. In most cases change_by() should be used.
|
||||
pub fn set_to(&mut self, amount: u32, cause: PoiseSource) {
|
||||
let amount = amount.min(self.maximum);
|
||||
self.last_change = (0.0, PoiseChange {
|
||||
@ -172,6 +188,7 @@ impl Poise {
|
||||
self.current = amount;
|
||||
}
|
||||
|
||||
/// Changes the current poise due to an in-game effect.
|
||||
pub fn change_by(&mut self, change: PoiseChange, impulse: Vec3<f32>) {
|
||||
self.current = ((self.current as i32 + change.amount).max(0) as u32).min(self.maximum);
|
||||
self.knockback = impulse;
|
||||
@ -181,32 +198,32 @@ impl Poise {
|
||||
});
|
||||
}
|
||||
|
||||
/// Resets current value to maximum
|
||||
pub fn reset(&mut self) { self.current = self.maximum; }
|
||||
|
||||
/// Sets the maximum and updates the current value to max out at the new
|
||||
/// maximum
|
||||
pub fn set_maximum(&mut self, amount: u32) {
|
||||
self.maximum = amount;
|
||||
self.current = self.current.min(self.maximum);
|
||||
}
|
||||
|
||||
/// Sets the `Poise` base_max
|
||||
fn set_base_max(&mut self, amount: u32) {
|
||||
self.base_max = amount;
|
||||
self.current = self.current.min(self.maximum);
|
||||
}
|
||||
|
||||
/// Resets the maximum to the base_max. Example use would be a potion
|
||||
/// wearing off
|
||||
pub fn reset_max(&mut self) { self.maximum = self.base_max; }
|
||||
|
||||
pub fn update_max_poise(&mut self, body: Option<Body>) {
|
||||
/// Sets the base_max based on the entity `Body`
|
||||
pub fn update_base_max(&mut self, body: Option<Body>) {
|
||||
if let Some(body) = body {
|
||||
self.set_base_max(body.base_poise());
|
||||
self.set_maximum(body.base_poise());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_max_poise(mut self, amount: u32) -> Self {
|
||||
self.maximum = amount;
|
||||
self.current = amount;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Poise {
|
||||
|
@ -30,7 +30,7 @@ pub struct Data {
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
println!("staggered");
|
||||
//println!("staggered");
|
||||
let mut update = StateUpdate::from(data);
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
|
@ -13,6 +13,8 @@ pub struct StaticData {
|
||||
pub buildup_duration: Duration,
|
||||
/// How long the state has until exiting
|
||||
pub recover_duration: Duration,
|
||||
/// Fraction of normal movement speed allowed during the state
|
||||
pub movement_speed: f32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -30,8 +32,10 @@ pub struct Data {
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
println!("stunned");
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_move(data, &mut update, self.static_data.movement_speed);
|
||||
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
if self.timer < self.static_data.buildup_duration {
|
||||
|
@ -101,9 +101,6 @@ impl<'a> System<'a> for Sys {
|
||||
// Check if entity is dodging
|
||||
let is_dodge = char_state_b_maybe.map_or(false, |c_s| c_s.is_melee_dodge());
|
||||
|
||||
// Check if entity is stunned
|
||||
let is_stunned = char_state_b_maybe.map_or(false, |c_s| c_s.is_stunned());
|
||||
|
||||
// Check if it is a hit
|
||||
if entity != b
|
||||
&& !health_b.is_dead
|
||||
@ -132,12 +129,8 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
|
||||
let change = damage.modify_damage(inventories.get(b), Some(*uid));
|
||||
let poise_change = if is_stunned {
|
||||
poise_change.set_zero()
|
||||
} else {
|
||||
poise_change.modify_poise_damage(inventories.get(b))
|
||||
};
|
||||
let change = damage.modify_damage(loadouts.get(b), Some(*uid));
|
||||
let poise_change = poise_change.modify_poise_damage(inventories.get(b));
|
||||
|
||||
server_emitter.emit(ServerEvent::Damage { entity: b, change });
|
||||
// Apply bleeding buff on melee hits with 10% chance
|
||||
@ -166,7 +159,7 @@ impl<'a> System<'a> for Sys {
|
||||
server_emitter.emit(ServerEvent::PoiseChange {
|
||||
entity: b,
|
||||
change: poise_change,
|
||||
kb_dir: *Dir::slerp(kb_dir, Dir::new(Vec3::unit_z()), 0.5),
|
||||
kb_dir: *kb_dir,
|
||||
});
|
||||
|
||||
attack.hit_count += 1;
|
||||
|
@ -167,8 +167,9 @@ impl<'a> System<'a> for Sys {
|
||||
poise.reset();
|
||||
*character_state = CharacterState::Stunned(common::states::stunned::Data {
|
||||
static_data: common::states::stunned::StaticData {
|
||||
buildup_duration: Duration::from_millis(100),
|
||||
recover_duration: Duration::from_millis(100),
|
||||
buildup_duration: Duration::from_millis(150),
|
||||
recover_duration: Duration::from_millis(150),
|
||||
movement_speed: 0.3,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: common::states::utils::StageSection::Buildup,
|
||||
@ -181,6 +182,7 @@ impl<'a> System<'a> for Sys {
|
||||
static_data: common::states::stunned::StaticData {
|
||||
buildup_duration: Duration::from_millis(500),
|
||||
recover_duration: Duration::from_millis(500),
|
||||
movement_speed: 0.1,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: common::states::utils::StageSection::Buildup,
|
||||
@ -211,8 +213,8 @@ impl<'a> System<'a> for Sys {
|
||||
poise.reset();
|
||||
*character_state = CharacterState::Staggered(common::states::staggered::Data {
|
||||
static_data: common::states::staggered::StaticData {
|
||||
buildup_duration: Duration::from_millis(5000),
|
||||
recover_duration: Duration::from_millis(250),
|
||||
buildup_duration: Duration::from_millis(3000),
|
||||
recover_duration: Duration::from_millis(500),
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: common::states::utils::StageSection::Buildup,
|
||||
|
@ -12,9 +12,9 @@ use common::{
|
||||
combat,
|
||||
comp::{
|
||||
self, aura, buff,
|
||||
chat::{KillSource, KillType}, CharacterState,
|
||||
object, Alignment, Body, Energy, EnergyChange, Group, Health, HealthChange, HealthSource,
|
||||
Inventory, Item, Player, Poise, PoiseChange, PoiseSource, Pos, Stats,
|
||||
chat::{KillSource, KillType},
|
||||
object, Alignment, Body, CharacterState, Energy, EnergyChange, Group, Health, HealthChange,
|
||||
HealthSource, Inventory, Item, Player, Poise, PoiseChange, PoiseSource, Pos, Stats,
|
||||
},
|
||||
effect::Effect,
|
||||
lottery::Lottery,
|
||||
@ -42,6 +42,7 @@ pub fn handle_poise(
|
||||
) {
|
||||
let ecs = &server.state.ecs();
|
||||
if let Some(character_state) = ecs.read_storage::<CharacterState>().get(entity) {
|
||||
// Entity is invincible to poise change during stunned/staggered character state
|
||||
if !character_state.is_stunned() {
|
||||
if let Some(poise) = ecs.write_storage::<Poise>().get_mut(entity) {
|
||||
poise.change_by(change, knockback_dir);
|
||||
@ -74,7 +75,7 @@ pub fn handle_knockback(server: &Server, entity: EcsEntity, impulse: Vec3<f32>)
|
||||
}
|
||||
let mut velocities = ecs.write_storage::<comp::Vel>();
|
||||
if let Some(vel) = velocities.get_mut(entity) {
|
||||
vel.0 = impulse;
|
||||
vel.0 += impulse;
|
||||
}
|
||||
if let Some(client) = clients.get(entity) {
|
||||
client.send_fallible(ServerGeneral::Knockback(impulse));
|
||||
@ -435,17 +436,26 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
|
||||
};
|
||||
|
||||
let pos = state.ecs().read_storage::<comp::Pos>().get(entity).cloned();
|
||||
let vel = state.ecs().read_storage::<comp::Vel>().get(entity).cloned();
|
||||
if let Some(pos) = pos {
|
||||
let _ = state
|
||||
.create_object(comp::Pos(pos.0 + Vec3::unit_z() * 0.25), match old_body {
|
||||
Some(common::comp::Body::Humanoid(_)) => object::Body::Pouch,
|
||||
Some(common::comp::Body::Golem(_)) => object::Body::Chest,
|
||||
Some(common::comp::Body::BipedLarge(_))
|
||||
| Some(common::comp::Body::QuadrupedLow(_)) => object::Body::MeatDrop,
|
||||
_ => object::Body::Steak,
|
||||
})
|
||||
.with(item)
|
||||
.build();
|
||||
if let Some(vel) = vel {
|
||||
let _ = state
|
||||
.create_object(comp::Pos(pos.0 + Vec3::unit_z() * 0.25), match old_body {
|
||||
Some(common::comp::Body::Humanoid(_)) => object::Body::Pouch,
|
||||
Some(common::comp::Body::Golem(_)) => object::Body::Chest,
|
||||
Some(common::comp::Body::BipedLarge(_))
|
||||
| Some(common::comp::Body::QuadrupedLow(_)) => object::Body::MeatDrop,
|
||||
_ => object::Body::Steak,
|
||||
})
|
||||
.with(vel)
|
||||
.with(item)
|
||||
.build();
|
||||
} else {
|
||||
error!(
|
||||
?entity,
|
||||
"Entity doesn't have a velocity, no bag is being dropped"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
error!(
|
||||
?entity,
|
||||
|
@ -22,7 +22,9 @@ pub mod sit;
|
||||
pub mod sneak;
|
||||
pub mod spin;
|
||||
pub mod spinmelee;
|
||||
pub mod staggered;
|
||||
pub mod stand;
|
||||
pub mod stunned;
|
||||
pub mod swim;
|
||||
pub mod swimwield;
|
||||
pub mod wield;
|
||||
@ -36,8 +38,8 @@ pub use self::{
|
||||
jump::JumpAnimation, leapmelee::LeapAnimation, repeater::RepeaterAnimation,
|
||||
roll::RollAnimation, run::RunAnimation, shockwave::ShockwaveAnimation, shoot::ShootAnimation,
|
||||
sit::SitAnimation, sneak::SneakAnimation, spin::SpinAnimation, spinmelee::SpinMeleeAnimation,
|
||||
stand::StandAnimation, swim::SwimAnimation, swimwield::SwimWieldAnimation,
|
||||
wield::WieldAnimation,
|
||||
staggered::StaggeredAnimation, stand::StandAnimation, stunned::StunnedAnimation,
|
||||
swim::SwimAnimation, swimwield::SwimWieldAnimation, wield::WieldAnimation,
|
||||
};
|
||||
use super::{make_bone, vek::*, FigureBoneData, Skeleton};
|
||||
use common::comp;
|
||||
|
@ -123,15 +123,19 @@ impl Animation for RunAnimation {
|
||||
* Quaternion::rotation_x(head_look.y + 0.45 * speednorm);
|
||||
next.head.scale = Vec3::one() * s_a.head_scale;
|
||||
|
||||
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + 1.0 + shortalt * -0.8);
|
||||
next.chest.position = Vec3::new(
|
||||
0.0,
|
||||
s_a.chest.0,
|
||||
s_a.chest.1 + 1.0 * speednorm + shortalt * -0.8,
|
||||
);
|
||||
next.chest.orientation = Quaternion::rotation_z(short * 0.06 + tilt * -0.6)
|
||||
* Quaternion::rotation_y(tilt * 1.6)
|
||||
* Quaternion::rotation_x(
|
||||
impact * 0.06 + shortalter * 0.035 + speed * -0.07 + (tilt.abs()),
|
||||
impact * 0.06 + shortalter * 0.035 + speednorm * -0.5 + (tilt.abs()),
|
||||
);
|
||||
|
||||
next.belt.position = Vec3::new(0.0, 0.25 + s_a.belt.0, 0.25 + s_a.belt.1);
|
||||
next.belt.orientation = Quaternion::rotation_x(0.1)
|
||||
next.belt.orientation = Quaternion::rotation_x(0.1 * speednorm)
|
||||
* Quaternion::rotation_z(short * 0.1 + tilt * -1.1)
|
||||
* Quaternion::rotation_y(tilt * 0.5);
|
||||
|
||||
@ -140,34 +144,36 @@ impl Animation for RunAnimation {
|
||||
Quaternion::rotation_x(-0.05 + short * 0.02 + noisea * 0.02 + noiseb * 0.02);
|
||||
|
||||
next.shorts.position = Vec3::new(0.0, 0.65 + s_a.shorts.0, 0.65 + s_a.shorts.1);
|
||||
next.shorts.orientation = Quaternion::rotation_x(0.2)
|
||||
next.shorts.orientation = Quaternion::rotation_x(0.2 * speednorm)
|
||||
* Quaternion::rotation_z(short * 0.25 + tilt * -1.5)
|
||||
* Quaternion::rotation_y(tilt * 0.7);
|
||||
|
||||
next.hand_l.position = Vec3::new(
|
||||
-s_a.hand.0 + foothorir * -1.3,
|
||||
3.0 + s_a.hand.1 + foothorir * -7.0 * speednorm,
|
||||
1.5 + s_a.hand.2 - foothorir * 5.5 * speednorm,
|
||||
-s_a.hand.0 + foothorir * -1.3 * speednorm,
|
||||
3.0 * speednorm + s_a.hand.1 + foothorir * -7.0 * speednorm,
|
||||
1.5 * speednorm + s_a.hand.2 - foothorir * 5.5 * speednorm,
|
||||
);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(0.6 + (footrotr * -1.2) * speednorm)
|
||||
* Quaternion::rotation_y(footrotr * 0.4);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(0.6 * speednorm + (footrotr * -1.2) * speednorm)
|
||||
* Quaternion::rotation_y(footrotr * 0.4 * speednorm);
|
||||
|
||||
next.hand_r.position = Vec3::new(
|
||||
s_a.hand.0 + foothoril * 1.3,
|
||||
3.0 + s_a.hand.1 + foothoril * -7.0 * speednorm,
|
||||
1.5 + s_a.hand.2 - foothoril * 5.5 * speednorm,
|
||||
s_a.hand.0 + foothoril * 1.3 * speednorm,
|
||||
3.0 * speednorm + s_a.hand.1 + foothoril * -7.0 * speednorm,
|
||||
1.5 * speednorm + s_a.hand.2 - foothoril * 5.5 * speednorm,
|
||||
);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(0.6 + (footrotl * -1.2) * speednorm)
|
||||
* Quaternion::rotation_y(footrotl * -0.4);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(0.6 * speednorm + (footrotl * -1.2) * speednorm)
|
||||
* Quaternion::rotation_y(footrotl * -0.4 * speednorm);
|
||||
|
||||
//
|
||||
next.foot_l.position = Vec3::new(
|
||||
-s_a.foot.0 + footstrafel * sideabs * 3.0 + tilt * -2.0,
|
||||
s_a.foot.1
|
||||
+ (1.0 - sideabs) * (-1.5 + foothoril * -10.5 * speednorm)
|
||||
+ (1.0 - sideabs) * (-1.5 * speednorm + foothoril * -10.5 * speednorm)
|
||||
+ (direction * 5.0).max(0.0),
|
||||
s_a.foot.2
|
||||
+ (1.0 - sideabs) * (2.0 + ((footvertl * -2.1 * speednorm).max(-1.0)))
|
||||
+ (1.0 - sideabs) * (2.0 * speednorm + ((footvertl * -2.1 * speednorm).max(-1.0)))
|
||||
+ side * ((footvertsl * 1.5).max(-1.0)),
|
||||
);
|
||||
next.foot_l.orientation = Quaternion::rotation_x(
|
||||
@ -179,10 +185,10 @@ impl Animation for RunAnimation {
|
||||
next.foot_r.position = Vec3::new(
|
||||
s_a.foot.0 + footstrafer * sideabs * 3.0 + tilt * -2.0,
|
||||
s_a.foot.1
|
||||
+ (1.0 - sideabs) * (-1.5 + foothorir * -10.5 * speednorm)
|
||||
+ (1.0 - sideabs) * (-1.5 * speednorm + foothorir * -10.5 * speednorm)
|
||||
+ (direction * 5.0).max(0.0),
|
||||
s_a.foot.2
|
||||
+ (1.0 - sideabs) * (2.0 + ((footvertr * -2.1 * speednorm).max(-1.0)))
|
||||
+ (1.0 - sideabs) * (2.0 * speednorm + ((footvertr * -2.1 * speednorm).max(-1.0)))
|
||||
+ side * ((footvertsr * -1.5).max(-1.0)),
|
||||
);
|
||||
next.foot_r.orientation = Quaternion::rotation_x(
|
||||
@ -253,7 +259,7 @@ impl Animation for RunAnimation {
|
||||
next.lantern.scale = Vec3::one() * 0.65;
|
||||
next.hold.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.position = Vec3::new(0.0, -0.3, 0.0) * s_a.scaler;
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.0) * s_a.scaler;
|
||||
next.torso.scale = Vec3::one() / 11.0 * s_a.scaler;
|
||||
|
||||
next.second.scale = match (
|
||||
|
213
voxygen/anim/src/character/staggered.rs
Normal file
213
voxygen/anim/src/character/staggered.rs
Normal file
@ -0,0 +1,213 @@
|
||||
use super::{
|
||||
super::{vek::*, Animation},
|
||||
CharacterSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::{comp::item::ToolKind, states::utils::StageSection};
|
||||
|
||||
pub struct StaggeredAnimation;
|
||||
|
||||
impl Animation for StaggeredAnimation {
|
||||
type Dependency = (
|
||||
Option<ToolKind>,
|
||||
Option<ToolKind>,
|
||||
f32,
|
||||
f64,
|
||||
Option<StageSection>,
|
||||
f64,
|
||||
bool,
|
||||
);
|
||||
type Skeleton = CharacterSkeleton;
|
||||
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
const UPDATE_FN: &'static [u8] = b"character_staggered\0";
|
||||
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_staggered")]
|
||||
#[allow(clippy::approx_constant)] // TODO: Pending review in #587
|
||||
fn update_skeleton_inner(
|
||||
skeleton: &Self::Skeleton,
|
||||
(
|
||||
active_tool_kind,
|
||||
_second_tool_kind,
|
||||
_velocity,
|
||||
global_time,
|
||||
stage_section,
|
||||
timer,
|
||||
wield_status,
|
||||
): Self::Dependency,
|
||||
anim_time: f64,
|
||||
rate: &mut f32,
|
||||
s_a: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
*rate = 1.0;
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let (movement1base, movement2) = match stage_section {
|
||||
Some(StageSection::Buildup) => ((anim_time as f32).powf(0.25), 0.0),
|
||||
Some(StageSection::Recover) => (1.0, (anim_time as f32).powf(4.0)),
|
||||
_ => (0.0, 0.0),
|
||||
};
|
||||
let pullback = 1.0 - movement2;
|
||||
let subtract = global_time - timer;
|
||||
let check = subtract - subtract.trunc();
|
||||
let mirror = (check - 0.5).signum() as f32;
|
||||
let movement1 = movement1base * pullback * mirror;
|
||||
let movement1abs = movement1base * pullback;
|
||||
|
||||
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
|
||||
next.head.orientation =
|
||||
Quaternion::rotation_x(movement1abs * -0.2) * Quaternion::rotation_z(movement1 * 0.3);
|
||||
next.shorts.orientation =
|
||||
Quaternion::rotation_x(movement1abs * 0.2) * Quaternion::rotation_z(movement1 * -0.3);
|
||||
next.belt.orientation =
|
||||
Quaternion::rotation_x(movement1abs * 0.1) * Quaternion::rotation_z(movement1 * -0.2);
|
||||
next.shorts.position = Vec3::new(0.0, s_a.shorts.0 + movement1abs * 1.0, s_a.shorts.1);
|
||||
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + movement1abs * -4.0);
|
||||
next.chest.orientation =
|
||||
Quaternion::rotation_x(movement1abs * -0.1) * Quaternion::rotation_z(movement1 * 1.0);
|
||||
if wield_status {
|
||||
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||
match active_tool_kind {
|
||||
Some(ToolKind::Sword) => {
|
||||
next.hand_l.position = Vec3::new(s_a.shl.0, s_a.shl.1, s_a.shl.2);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(s_a.shl.3) * Quaternion::rotation_y(s_a.shl.4);
|
||||
next.hand_r.position = Vec3::new(s_a.shr.0, s_a.shr.1, s_a.shr.2);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(s_a.shr.3) * Quaternion::rotation_y(s_a.shr.4);
|
||||
|
||||
next.control.position = Vec3::new(s_a.sc.0, s_a.sc.1, s_a.sc.2);
|
||||
next.control.orientation = Quaternion::rotation_x(s_a.sc.3);
|
||||
},
|
||||
Some(ToolKind::Axe) => {
|
||||
next.hand_l.position = Vec3::new(s_a.ahl.0, s_a.ahl.1, s_a.ahl.2);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(s_a.ahl.3) * Quaternion::rotation_y(s_a.ahl.4);
|
||||
next.hand_r.position = Vec3::new(s_a.ahr.0, s_a.ahr.1, s_a.ahr.2);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(s_a.ahr.3) * Quaternion::rotation_z(s_a.ahr.5);
|
||||
|
||||
next.control.position = Vec3::new(s_a.ac.0, s_a.ac.1, s_a.ac.2);
|
||||
next.control.orientation = Quaternion::rotation_x(s_a.ac.3)
|
||||
* Quaternion::rotation_y(s_a.ac.4)
|
||||
* Quaternion::rotation_z(s_a.ac.5);
|
||||
},
|
||||
Some(ToolKind::Hammer) => {
|
||||
next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(s_a.hhl.3) * Quaternion::rotation_y(s_a.hhl.4);
|
||||
next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1, s_a.hhr.2);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(s_a.hhr.3) * Quaternion::rotation_y(s_a.hhr.4);
|
||||
|
||||
next.control.position = Vec3::new(s_a.hc.0, s_a.hc.1, s_a.hc.2);
|
||||
next.control.orientation = Quaternion::rotation_x(s_a.hc.3)
|
||||
* Quaternion::rotation_y(s_a.hc.4)
|
||||
* Quaternion::rotation_z(s_a.hc.5);
|
||||
},
|
||||
Some(ToolKind::Staff) | Some(ToolKind::Sceptre) => {
|
||||
next.hand_r.position = Vec3::new(s_a.sthr.0, s_a.sthr.1, s_a.sthr.2);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(s_a.sthr.3) * Quaternion::rotation_y(s_a.sthr.4);
|
||||
|
||||
next.control.position = Vec3::new(s_a.stc.0, s_a.stc.1, s_a.stc.2);
|
||||
|
||||
next.hand_l.position = Vec3::new(s_a.sthl.0, s_a.sthl.1, s_a.sthl.2);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(s_a.sthl.3);
|
||||
|
||||
next.control.orientation = Quaternion::rotation_x(s_a.stc.3)
|
||||
* Quaternion::rotation_y(s_a.stc.4)
|
||||
* Quaternion::rotation_z(s_a.stc.5);
|
||||
},
|
||||
Some(ToolKind::Bow) => {
|
||||
next.hand_l.position = Vec3::new(s_a.bhl.0, s_a.bhl.1, s_a.bhl.2);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(s_a.bhl.3);
|
||||
next.hand_r.position = Vec3::new(s_a.bhr.0, s_a.bhr.1, s_a.bhr.2);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(s_a.bhr.3);
|
||||
|
||||
next.hold.position = Vec3::new(0.0, -1.0, -5.2);
|
||||
next.hold.orientation = Quaternion::rotation_x(-1.57);
|
||||
next.hold.scale = Vec3::one() * 1.0;
|
||||
|
||||
next.control.position = Vec3::new(s_a.bc.0, s_a.bc.1, s_a.bc.2);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_y(s_a.bc.4) * Quaternion::rotation_z(s_a.bc.5);
|
||||
},
|
||||
Some(ToolKind::Debug) => {
|
||||
next.hand_l.position = Vec3::new(-7.0, 4.0, 3.0);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(1.27);
|
||||
next.main.position = Vec3::new(-5.0, 5.0, 23.0);
|
||||
next.main.orientation = Quaternion::rotation_x(3.14);
|
||||
},
|
||||
Some(ToolKind::Farming) => {
|
||||
next.hand_l.position = Vec3::new(9.0, 1.0, 1.0);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(1.57);
|
||||
next.hand_r.position = Vec3::new(9.0, 1.0, 11.0);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(1.57);
|
||||
next.main.position = Vec3::new(7.5, 7.5, 13.2);
|
||||
next.main.orientation = Quaternion::rotation_y(3.14);
|
||||
|
||||
next.control.position = Vec3::new(-11.0, 1.8, 4.0);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
} else {
|
||||
if mirror > 0.0 {
|
||||
next.hand_r.position = Vec3::new(
|
||||
s_a.hand.0 + movement1abs * -9.0,
|
||||
s_a.hand.1 + movement1 * 9.0,
|
||||
s_a.hand.2 + movement1 * 5.0,
|
||||
);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(movement1 * 1.2)
|
||||
* Quaternion::rotation_y(movement1 * 1.5);
|
||||
next.hand_l.position = Vec3::new(
|
||||
-s_a.hand.0,
|
||||
s_a.hand.1 + movement1abs * 3.0,
|
||||
s_a.hand.2 + movement1abs * -1.0,
|
||||
);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(movement1abs * 0.5)
|
||||
* Quaternion::rotation_y(movement1 * 0.3);
|
||||
next.foot_l.position =
|
||||
Vec3::new(-s_a.foot.0, s_a.foot.1 + movement1abs * -7.0, s_a.foot.2);
|
||||
next.foot_l.orientation = Quaternion::rotation_x(movement1abs * -1.2)
|
||||
* Quaternion::rotation_z(movement1 * 0.8);
|
||||
|
||||
next.foot_r.position = Vec3::new(
|
||||
s_a.foot.0 + movement1 * -5.0,
|
||||
s_a.foot.1 + movement1abs * 3.0,
|
||||
s_a.foot.2,
|
||||
);
|
||||
next.foot_r.orientation = Quaternion::rotation_z(movement1 * 0.6);
|
||||
} else {
|
||||
next.hand_l.position = Vec3::new(
|
||||
-s_a.hand.0 + movement1abs * 9.0,
|
||||
s_a.hand.1 + movement1abs * 9.0,
|
||||
s_a.hand.2 + movement1abs * 5.0,
|
||||
);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(movement1abs * 1.2)
|
||||
* Quaternion::rotation_y(movement1 * 1.5);
|
||||
next.hand_r.position = Vec3::new(
|
||||
s_a.hand.0,
|
||||
s_a.hand.1 + movement1abs * 3.0,
|
||||
s_a.hand.2 + movement1abs * -1.0,
|
||||
);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(movement1abs * 0.5)
|
||||
* Quaternion::rotation_y(movement1 * 0.3);
|
||||
next.foot_r.position =
|
||||
Vec3::new(s_a.foot.0, s_a.foot.1 + movement1abs * -7.0, s_a.foot.2);
|
||||
next.foot_r.orientation = Quaternion::rotation_x(movement1abs * -1.2)
|
||||
* Quaternion::rotation_z(movement1 * 0.8);
|
||||
next.foot_l.position = Vec3::new(
|
||||
-s_a.foot.0 + movement1 * -5.0,
|
||||
s_a.foot.1 + movement1abs * 3.0,
|
||||
s_a.foot.2,
|
||||
);
|
||||
next.foot_l.orientation = Quaternion::rotation_z(movement1 * 0.6);
|
||||
};
|
||||
};
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.0) * s_a.scaler;
|
||||
next.torso.orientation = Quaternion::rotation_z(0.0);
|
||||
|
||||
next
|
||||
}
|
||||
}
|
177
voxygen/anim/src/character/stunned.rs
Normal file
177
voxygen/anim/src/character/stunned.rs
Normal file
@ -0,0 +1,177 @@
|
||||
use super::{
|
||||
super::{vek::*, Animation},
|
||||
CharacterSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::{comp::item::ToolKind, states::utils::StageSection};
|
||||
|
||||
pub struct StunnedAnimation;
|
||||
|
||||
impl Animation for StunnedAnimation {
|
||||
type Dependency = (
|
||||
Option<ToolKind>,
|
||||
Option<ToolKind>,
|
||||
f32,
|
||||
f64,
|
||||
Option<StageSection>,
|
||||
f64,
|
||||
bool,
|
||||
);
|
||||
type Skeleton = CharacterSkeleton;
|
||||
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
const UPDATE_FN: &'static [u8] = b"character_stunned\0";
|
||||
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_stunned")]
|
||||
#[allow(clippy::approx_constant)] // TODO: Pending review in #587
|
||||
fn update_skeleton_inner(
|
||||
skeleton: &Self::Skeleton,
|
||||
(
|
||||
active_tool_kind,
|
||||
_second_tool_kind,
|
||||
_velocity,
|
||||
global_time,
|
||||
stage_section,
|
||||
timer,
|
||||
wield_status,
|
||||
): Self::Dependency,
|
||||
anim_time: f64,
|
||||
rate: &mut f32,
|
||||
s_a: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
*rate = 1.0;
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let (movement1base, movement2) = match stage_section {
|
||||
Some(StageSection::Buildup) => ((anim_time as f32).powf(0.25), 0.0),
|
||||
Some(StageSection::Recover) => (1.0, (anim_time as f32).powf(4.0)),
|
||||
_ => (0.0, 0.0),
|
||||
};
|
||||
let pullback = 1.0 - movement2;
|
||||
let subtract = global_time - timer;
|
||||
let check = subtract - subtract.trunc();
|
||||
let mirror = (check - 0.5).signum() as f32;
|
||||
let movement1 = movement1base * pullback * mirror;
|
||||
let movement1abs = movement1base * pullback;
|
||||
println!("wield {}", wield_status);
|
||||
|
||||
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
|
||||
next.head.orientation = Quaternion::rotation_z(movement1 * 0.3);
|
||||
next.shorts.orientation =
|
||||
Quaternion::rotation_x(movement1abs * -0.2) * Quaternion::rotation_z(movement1 * -0.3);
|
||||
next.belt.orientation =
|
||||
Quaternion::rotation_x(movement1abs * -0.1) * Quaternion::rotation_z(movement1 * -0.2);
|
||||
|
||||
next.chest.orientation =
|
||||
Quaternion::rotation_x(movement1abs * 0.3) * Quaternion::rotation_z(movement1 * 0.5);
|
||||
if wield_status {
|
||||
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||
match active_tool_kind {
|
||||
Some(ToolKind::Sword) => {
|
||||
next.hand_l.position = Vec3::new(s_a.shl.0, s_a.shl.1, s_a.shl.2);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(s_a.shl.3) * Quaternion::rotation_y(s_a.shl.4);
|
||||
next.hand_r.position = Vec3::new(s_a.shr.0, s_a.shr.1, s_a.shr.2);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(s_a.shr.3) * Quaternion::rotation_y(s_a.shr.4);
|
||||
|
||||
next.control.position = Vec3::new(s_a.sc.0, s_a.sc.1, s_a.sc.2);
|
||||
next.control.orientation = Quaternion::rotation_x(s_a.sc.3);
|
||||
},
|
||||
Some(ToolKind::Axe) => {
|
||||
next.hand_l.position = Vec3::new(s_a.ahl.0, s_a.ahl.1, s_a.ahl.2);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(s_a.ahl.3) * Quaternion::rotation_y(s_a.ahl.4);
|
||||
next.hand_r.position = Vec3::new(s_a.ahr.0, s_a.ahr.1, s_a.ahr.2);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(s_a.ahr.3) * Quaternion::rotation_z(s_a.ahr.5);
|
||||
|
||||
next.control.position = Vec3::new(s_a.ac.0, s_a.ac.1, s_a.ac.2);
|
||||
next.control.orientation = Quaternion::rotation_x(s_a.ac.3)
|
||||
* Quaternion::rotation_y(s_a.ac.4)
|
||||
* Quaternion::rotation_z(s_a.ac.5);
|
||||
},
|
||||
Some(ToolKind::Hammer) => {
|
||||
next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(s_a.hhl.3) * Quaternion::rotation_y(s_a.hhl.4);
|
||||
next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1, s_a.hhr.2);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(s_a.hhr.3) * Quaternion::rotation_y(s_a.hhr.4);
|
||||
|
||||
next.control.position = Vec3::new(s_a.hc.0, s_a.hc.1, s_a.hc.2);
|
||||
next.control.orientation = Quaternion::rotation_x(s_a.hc.3)
|
||||
* Quaternion::rotation_y(s_a.hc.4)
|
||||
* Quaternion::rotation_z(s_a.hc.5);
|
||||
},
|
||||
Some(ToolKind::Staff) | Some(ToolKind::Sceptre) => {
|
||||
next.hand_r.position = Vec3::new(s_a.sthr.0, s_a.sthr.1, s_a.sthr.2);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(s_a.sthr.3) * Quaternion::rotation_y(s_a.sthr.4);
|
||||
|
||||
next.control.position = Vec3::new(s_a.stc.0, s_a.stc.1, s_a.stc.2);
|
||||
|
||||
next.hand_l.position = Vec3::new(s_a.sthl.0, s_a.sthl.1, s_a.sthl.2);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(s_a.sthl.3);
|
||||
|
||||
next.control.orientation = Quaternion::rotation_x(s_a.stc.3)
|
||||
* Quaternion::rotation_y(s_a.stc.4)
|
||||
* Quaternion::rotation_z(s_a.stc.5);
|
||||
},
|
||||
Some(ToolKind::Bow) => {
|
||||
next.hand_l.position = Vec3::new(s_a.bhl.0, s_a.bhl.1, s_a.bhl.2);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(s_a.bhl.3);
|
||||
next.hand_r.position = Vec3::new(s_a.bhr.0, s_a.bhr.1, s_a.bhr.2);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(s_a.bhr.3);
|
||||
|
||||
next.hold.position = Vec3::new(0.0, -1.0, -5.2);
|
||||
next.hold.orientation = Quaternion::rotation_x(-1.57);
|
||||
next.hold.scale = Vec3::one() * 1.0;
|
||||
|
||||
next.control.position = Vec3::new(s_a.bc.0, s_a.bc.1, s_a.bc.2);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_y(s_a.bc.4) * Quaternion::rotation_z(s_a.bc.5);
|
||||
},
|
||||
Some(ToolKind::Debug) => {
|
||||
next.hand_l.position = Vec3::new(-7.0, 4.0, 3.0);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(1.27);
|
||||
next.main.position = Vec3::new(-5.0, 5.0, 23.0);
|
||||
next.main.orientation = Quaternion::rotation_x(3.14);
|
||||
},
|
||||
Some(ToolKind::Farming) => {
|
||||
next.hand_l.position = Vec3::new(9.0, 1.0, 1.0);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(1.57);
|
||||
next.hand_r.position = Vec3::new(9.0, 1.0, 11.0);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(1.57);
|
||||
next.main.position = Vec3::new(7.5, 7.5, 13.2);
|
||||
next.main.orientation = Quaternion::rotation_y(3.14);
|
||||
|
||||
next.control.position = Vec3::new(-11.0, 1.8, 4.0);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
} else {
|
||||
if mirror > 0.0 {
|
||||
next.hand_r.position = Vec3::new(
|
||||
s_a.hand.0 + movement1abs * -4.0,
|
||||
s_a.hand.1 + movement1 * 7.0,
|
||||
s_a.hand.2 + movement1 * 6.0,
|
||||
);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(movement1 * 1.2)
|
||||
* Quaternion::rotation_y(movement1 * 1.2);
|
||||
} else {
|
||||
next.hand_l.position = Vec3::new(
|
||||
-s_a.hand.0 + movement1abs * 4.0,
|
||||
s_a.hand.1 + movement1abs * 7.0,
|
||||
s_a.hand.2 + movement1abs * 6.0,
|
||||
);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(movement1abs * 1.2)
|
||||
* Quaternion::rotation_y(movement1 * 1.2);
|
||||
};
|
||||
};
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.0) * s_a.scaler;
|
||||
next.torso.orientation = Quaternion::rotation_z(0.0);
|
||||
|
||||
next
|
||||
}
|
||||
}
|
@ -148,8 +148,7 @@ pub fn init() {
|
||||
// "Debounces" events since I can't find the option to do this in the latest
|
||||
// `notify`
|
||||
thread::spawn(move || {
|
||||
let mut modified_paths = HashSet::new();
|
||||
|
||||
let mut modified_paths = std::collections::HashSet::new();
|
||||
while let Ok(path) = reload_recv.recv() {
|
||||
modified_paths.insert(path);
|
||||
// Wait for any additional modify events before reloading
|
||||
|
@ -1122,6 +1122,62 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Stunned(s) => {
|
||||
let stage_time = s.timer.as_secs_f64();
|
||||
let wield_status = s.was_wielded;
|
||||
let stage_progress = match s.stage_section {
|
||||
StageSection::Buildup => {
|
||||
stage_time / s.static_data.buildup_duration.as_secs_f64()
|
||||
},
|
||||
StageSection::Recover => {
|
||||
stage_time / s.static_data.recover_duration.as_secs_f64()
|
||||
},
|
||||
_ => 0.0,
|
||||
};
|
||||
anim::character::StunnedAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(
|
||||
active_tool_kind,
|
||||
second_tool_kind,
|
||||
vel.0.magnitude(),
|
||||
time,
|
||||
Some(s.stage_section),
|
||||
state.state_time,
|
||||
wield_status,
|
||||
),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Staggered(s) => {
|
||||
let stage_time = s.timer.as_secs_f64();
|
||||
let wield_status = s.was_wielded;
|
||||
let stage_progress = match s.stage_section {
|
||||
StageSection::Buildup => {
|
||||
stage_time / s.static_data.buildup_duration.as_secs_f64()
|
||||
},
|
||||
StageSection::Recover => {
|
||||
stage_time / s.static_data.recover_duration.as_secs_f64()
|
||||
},
|
||||
_ => 0.0,
|
||||
};
|
||||
anim::character::StaggeredAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(
|
||||
active_tool_kind,
|
||||
second_tool_kind,
|
||||
vel.0.magnitude(),
|
||||
time,
|
||||
Some(s.stage_section),
|
||||
state.state_time,
|
||||
wield_status,
|
||||
),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::BasicBeam(s) => {
|
||||
let stage_time = s.timer.as_secs_f64();
|
||||
let stage_progress = match s.stage_section {
|
||||
|
Loading…
Reference in New Issue
Block a user