Merge branch 'james/hammer-axe-bow-skillz' into 'master'

Add 3rd skill for hammer, bow, and axe

Closes #766, #765, and #764

See merge request veloren/veloren!1399
This commit is contained in:
Samuel Keiffer 2020-10-15 01:34:53 +00:00
commit 4a90f7c088
30 changed files with 1715 additions and 211 deletions

View File

@ -21,6 +21,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Theropod body
- Several new animals
- Item quality indicators
- Added a jump/burst attack for the bow to the skillbar
- Gave the axe a third attack
- A new secondary charged melee attack for the hammer
### Changed
@ -46,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Reworked healing sceptre
- Split out the sections of the server settings that can be edited and saved by the server.
- Revamped structure of where settings, logs, and game saves are stored so that almost everything is in one place.
- Moved hammer leap attack to skillbar
### Removed

View File

@ -73,7 +73,6 @@
),
GliderClose: (
files: [
// Event Missing or not implemented?
"voxygen.audio.sfx.glider_close",
],
threshold: 0.5,
@ -112,12 +111,18 @@
],
threshold: 0.7,
),
Attack(DashMelee, Sword): (
Attack(DashMelee(Swing), Sword): (
files: [
"voxygen.audio.sfx.abilities.sword_dash",
],
threshold: 0.8,
),
Attack(SpinMelee(Swing), Sword): (
files: [
"voxygen.audio.sfx.abilities.swing_sword",
],
threshold: 0.7,
),
Inventory(CollectedTool(Sword)): (
files: [
"voxygen.audio.sfx.inventory.pickup_sword",
@ -146,9 +151,15 @@
],
threshold: 0.7,
),
Attack(LeapMelee, Hammer): (
Attack(ChargedMelee(Swing), Hammer): (
files: [
//
"voxygen.audio.sfx.abilities.swing",
],
threshold: 0.7,
),
Attack(LeapMelee(Swing), Hammer): (
files: [
"voxygen.audio.sfx.abilities.swing",
],
threshold: 0.8,
),
@ -180,7 +191,13 @@
],
threshold: 0.7,
),
Attack(SpinMelee, Axe): (
Attack(SpinMelee(Swing), Axe): (
files: [
"voxygen.audio.sfx.abilities.swing",
],
threshold: 0.8,
),
Attack(LeapMelee(Swing), Axe): (
files: [
"voxygen.audio.sfx.abilities.swing",
],
@ -276,7 +293,7 @@
],
threshold: 0.8,
),
Attack(DashMelee, Dagger): (
Attack(DashMelee(Swing), Dagger): (
files: [
"voxygen.audio.sfx.abilities.sword_dash",
],

Binary file not shown.

BIN
assets/voxygen/element/icons/skill_axe_leap_slash.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/icons/skill_bow_jump_burst.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/icons/skill_hammergolf.png (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -18,14 +18,16 @@ pub enum CharacterAbilityType {
BasicMelee,
BasicRanged,
Boost,
ChargedMelee(StageSection),
ChargedRanged,
DashMelee,
DashMelee(StageSection),
BasicBlock,
ComboMelee(StageSection, u32),
LeapMelee,
SpinMelee,
LeapMelee(StageSection),
SpinMelee(StageSection),
GroundShockwave,
BasicBeam,
RepeaterRanged,
}
impl From<&CharacterState> for CharacterAbilityType {
@ -34,14 +36,16 @@ impl From<&CharacterState> for CharacterAbilityType {
CharacterState::BasicMelee(_) => Self::BasicMelee,
CharacterState::BasicRanged(_) => Self::BasicRanged,
CharacterState::Boost(_) => Self::Boost,
CharacterState::DashMelee(_) => Self::DashMelee,
CharacterState::DashMelee(data) => Self::DashMelee(data.stage_section),
CharacterState::BasicBlock => Self::BasicBlock,
CharacterState::LeapMelee(_) => Self::LeapMelee,
CharacterState::LeapMelee(data) => Self::LeapMelee(data.stage_section),
CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage_section, data.stage),
CharacterState::SpinMelee(_) => Self::SpinMelee,
CharacterState::SpinMelee(data) => Self::SpinMelee(data.stage_section),
CharacterState::ChargedMelee(data) => Self::ChargedMelee(data.stage_section),
CharacterState::ChargedRanged(_) => Self::ChargedRanged,
CharacterState::GroundShockwave(_) => Self::ChargedRanged,
CharacterState::BasicBeam(_) => Self::BasicBeam,
CharacterState::RepeaterRanged(_) => Self::RepeaterRanged,
_ => Self::BasicMelee,
}
}
@ -69,6 +73,20 @@ pub enum CharacterAbility {
projectile_gravity: Option<Gravity>,
projectile_speed: f32,
},
RepeaterRanged {
energy_cost: u32,
movement_duration: Duration,
buildup_duration: Duration,
shoot_duration: Duration,
recover_duration: Duration,
leap: Option<f32>,
projectile: Projectile,
projectile_body: Body,
projectile_light: Option<LightEmitter>,
projectile_gravity: Option<Gravity>,
projectile_speed: f32,
reps_remaining: u32,
},
Boost {
duration: Duration,
only_up: bool,
@ -103,10 +121,16 @@ pub enum CharacterAbility {
},
LeapMelee {
energy_cost: u32,
movement_duration: Duration,
buildup_duration: Duration,
movement_duration: Duration,
swing_duration: Duration,
recover_duration: Duration,
base_damage: u32,
range: f32,
max_angle: f32,
knockback: f32,
forward_leap_strength: f32,
vertical_leap_strength: f32,
},
SpinMelee {
buildup_duration: Duration,
@ -122,6 +146,19 @@ pub enum CharacterAbility {
forward_speed: f32,
num_spins: u32,
},
ChargedMelee {
energy_cost: u32,
energy_drain: u32,
initial_damage: u32,
max_damage: u32,
initial_knockback: f32,
max_knockback: f32,
range: f32,
max_angle: f32,
charge_duration: Duration,
swing_duration: Duration,
recover_duration: Duration,
},
ChargedRanged {
energy_cost: u32,
energy_drain: u32,
@ -203,6 +240,14 @@ impl CharacterAbility {
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
CharacterAbility::ChargedMelee { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
CharacterAbility::RepeaterRanged { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
CharacterAbility::GroundShockwave { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
@ -420,17 +465,32 @@ impl From<&CharacterAbility> for CharacterState {
}),
CharacterAbility::LeapMelee {
energy_cost: _,
movement_duration,
buildup_duration,
movement_duration,
swing_duration,
recover_duration,
base_damage,
knockback,
range,
max_angle,
forward_leap_strength,
vertical_leap_strength,
} => CharacterState::LeapMelee(leap_melee::Data {
initialize: true,
static_data: leap_melee::StaticData {
buildup_duration: *buildup_duration,
movement_duration: *movement_duration,
swing_duration: *swing_duration,
recover_duration: *recover_duration,
base_damage: *base_damage,
knockback: *knockback,
range: *range,
max_angle: *max_angle,
forward_leap_strength: *forward_leap_strength,
vertical_leap_strength: *vertical_leap_strength,
},
timer: Duration::default(),
stage_section: StageSection::Buildup,
exhausted: false,
movement_duration: *movement_duration,
buildup_duration: *buildup_duration,
recover_duration: *recover_duration,
base_damage: *base_damage,
}),
CharacterAbility::SpinMelee {
buildup_duration,
@ -465,6 +525,37 @@ impl From<&CharacterAbility> for CharacterState {
stage_section: StageSection::Buildup,
exhausted: false,
}),
CharacterAbility::ChargedMelee {
energy_cost,
energy_drain,
initial_damage,
max_damage,
initial_knockback,
max_knockback,
charge_duration,
swing_duration,
recover_duration,
range,
max_angle,
} => CharacterState::ChargedMelee(charged_melee::Data {
static_data: charged_melee::StaticData {
energy_cost: *energy_cost,
energy_drain: *energy_drain,
initial_damage: *initial_damage,
max_damage: *max_damage,
initial_knockback: *initial_knockback,
max_knockback: *max_knockback,
range: *range,
max_angle: *max_angle,
charge_duration: *charge_duration,
swing_duration: *swing_duration,
recover_duration: *recover_duration,
},
stage_section: StageSection::Charge,
timer: Duration::default(),
exhausted: false,
charge_amount: 0.0,
}),
CharacterAbility::ChargedRanged {
energy_cost: _,
energy_drain,
@ -497,6 +588,36 @@ impl From<&CharacterAbility> for CharacterState {
initial_projectile_speed: *initial_projectile_speed,
max_projectile_speed: *max_projectile_speed,
}),
CharacterAbility::RepeaterRanged {
energy_cost: _,
movement_duration,
buildup_duration,
shoot_duration,
recover_duration,
leap,
projectile,
projectile_body,
projectile_light,
projectile_gravity,
projectile_speed,
reps_remaining,
} => CharacterState::RepeaterRanged(repeater_ranged::Data {
static_data: repeater_ranged::StaticData {
movement_duration: *movement_duration,
buildup_duration: *buildup_duration,
shoot_duration: *shoot_duration,
recover_duration: *recover_duration,
leap: *leap,
projectile: projectile.clone(),
projectile_body: *projectile_body,
projectile_light: *projectile_light,
projectile_gravity: *projectile_gravity,
projectile_speed: *projectile_speed,
},
timer: Duration::default(),
stage_section: StageSection::Movement,
reps_remaining: *reps_remaining,
}),
CharacterAbility::GroundShockwave {
energy_cost: _,
buildup_duration,

View File

@ -69,6 +69,10 @@ pub enum CharacterState {
SpinMelee(spin_melee::Data),
/// A charged ranged attack (e.g. bow)
ChargedRanged(charged_ranged::Data),
/// A charged melee attack
ChargedMelee(charged_melee::Data),
/// A repeating ranged attack
RepeaterRanged(repeater_ranged::Data),
/// A ground shockwave attack
GroundShockwave(ground_shockwave::Data),
/// A continuous attack that affects all creatures in a cone originating
@ -87,7 +91,9 @@ impl CharacterState {
| CharacterState::BasicBlock
| CharacterState::LeapMelee(_)
| CharacterState::SpinMelee(_)
| CharacterState::ChargedMelee(_)
| CharacterState::ChargedRanged(_)
| CharacterState::RepeaterRanged(_)
| CharacterState::GroundShockwave(_)
| CharacterState::BasicBeam(_)
)
@ -101,7 +107,9 @@ impl CharacterState {
| CharacterState::ComboMelee(_)
| CharacterState::LeapMelee(_)
| CharacterState::SpinMelee(_)
| CharacterState::ChargedMelee(_)
| CharacterState::ChargedRanged(_)
| CharacterState::RepeaterRanged(_)
| CharacterState::GroundShockwave(_)
| CharacterState::BasicBeam(_)
)
@ -115,7 +123,9 @@ impl CharacterState {
| CharacterState::ComboMelee(_)
| CharacterState::BasicBlock
| CharacterState::LeapMelee(_)
| CharacterState::ChargedMelee(_)
| CharacterState::ChargedRanged(_)
| CharacterState::RepeaterRanged(_)
| CharacterState::GroundShockwave(_)
| CharacterState::BasicBeam(_)
)

View File

@ -226,6 +226,19 @@ impl Tool {
forward_speed: 0.0,
num_spins: 1,
},
LeapMelee {
energy_cost: 450,
buildup_duration: Duration::from_millis(200),
movement_duration: Duration::from_millis(200),
swing_duration: Duration::from_millis(200),
recover_duration: Duration::from_millis(200),
base_damage: (240.0 * self.base_power()) as u32,
knockback: 12.0,
range: 4.5,
max_angle: 30.0,
forward_leap_strength: 28.0,
vertical_leap_strength: 8.0,
},
],
Hammer(_) => vec![
BasicMelee {
@ -237,12 +250,31 @@ impl Tool {
range: 3.5,
max_angle: 20.0,
},
LeapMelee {
energy_cost: 800,
movement_duration: Duration::from_millis(500),
buildup_duration: Duration::from_millis(1000),
ChargedMelee {
energy_cost: 1,
energy_drain: 300,
initial_damage: (10.0 * self.base_power()) as u32,
max_damage: (170.0 * self.base_power()) as u32,
initial_knockback: 10.0,
max_knockback: 60.0,
range: 3.5,
max_angle: 30.0,
charge_duration: Duration::from_millis(1200),
swing_duration: Duration::from_millis(400),
recover_duration: Duration::from_millis(100),
},
LeapMelee {
energy_cost: 700,
buildup_duration: Duration::from_millis(100),
movement_duration: Duration::from_millis(800),
swing_duration: Duration::from_millis(150),
recover_duration: Duration::from_millis(200),
base_damage: (240.0 * self.base_power()) as u32,
knockback: 25.0,
range: 4.5,
max_angle: 360.0,
forward_leap_strength: 28.0,
vertical_leap_strength: 8.0,
},
],
Farming(_) => vec![BasicMelee {
@ -293,6 +325,31 @@ impl Tool {
initial_projectile_speed: 100.0,
max_projectile_speed: 500.0,
},
RepeaterRanged {
energy_cost: 450,
movement_duration: Duration::from_millis(300),
buildup_duration: Duration::from_millis(200),
shoot_duration: Duration::from_millis(200),
recover_duration: Duration::from_millis(800),
leap: Some(10.0),
projectile: Projectile {
hit_solid: vec![projectile::Effect::Stick],
hit_entity: vec![
projectile::Effect::Damage((-40.0 * self.base_power()) as i32),
projectile::Effect::Knockback(10.0),
projectile::Effect::RewardEnergy(50),
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(15),
owner: None,
ignore_group: true,
},
projectile_body: Body::Object(object::Body::Arrow),
projectile_light: None,
projectile_gravity: Some(Gravity(0.2)),
projectile_speed: 100.0,
reps_remaining: 5,
},
],
Dagger(_) => vec![BasicMelee {
energy_cost: 0,

View File

@ -0,0 +1,200 @@
use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
states::utils::{StageSection, *},
sys::character_behavior::*,
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
/// Separated out to condense update portions of character state
pub struct StaticData {
/// How much energy is drained per second when charging
pub energy_drain: u32,
/// Energy cost per attack
pub energy_cost: u32,
/// How much damage is dealt with no charge
pub initial_damage: u32,
/// How much damage is dealt with max charge
pub max_damage: u32,
/// How much knockback there is with no charge
pub initial_knockback: f32,
/// How much knockback there is at max charge
pub max_knockback: f32,
/// Max range
pub range: f32,
/// Max angle (45.0 will give you a 90.0 angle window)
pub max_angle: f32,
/// How long it takes to charge the weapon to max damage and knockback
pub charge_duration: Duration,
/// How long the weapon is swinging for
pub swing_duration: Duration,
/// How long the state has until exiting
pub recover_duration: Duration,
}
#[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,
/// Checks what section a stage is in
pub stage_section: StageSection,
/// Timer for each stage
pub timer: Duration,
/// Whether the attack fired already
pub exhausted: bool,
/// How much the attack charged by
pub charge_amount: f32,
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_move(data, &mut update, 0.7);
handle_jump(data, &mut update);
match self.stage_section {
StageSection::Charge => {
if data.inputs.secondary.is_pressed()
&& update.energy.current() >= self.static_data.energy_cost
&& self.timer < self.static_data.charge_duration
{
let charge = (self.timer.as_secs_f32()
/ self.static_data.charge_duration.as_secs_f32())
.min(1.0);
// Charge the attack
update.character = CharacterState::ChargedMelee(Data {
static_data: self.static_data,
stage_section: self.stage_section,
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
exhausted: self.exhausted,
charge_amount: charge,
});
// Consumes energy if there's enough left and RMB is held down
update.energy.change_by(
-(self.static_data.energy_drain as f32 * data.dt.0) as i32,
EnergySource::Ability,
);
} else if data.inputs.secondary.is_pressed()
&& update.energy.current() >= self.static_data.energy_cost
{
// Maintains charge
update.character = CharacterState::ChargedMelee(Data {
static_data: self.static_data,
stage_section: self.stage_section,
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
exhausted: self.exhausted,
charge_amount: self.charge_amount,
});
// Consumes energy if there's enough left and RMB is held down
update.energy.change_by(
-(self.static_data.energy_drain as f32 * data.dt.0 / 5.0) as i32,
EnergySource::Ability,
);
} else {
// Transitions to swing
update.character = CharacterState::ChargedMelee(Data {
static_data: self.static_data,
stage_section: StageSection::Swing,
timer: Duration::default(),
exhausted: self.exhausted,
charge_amount: self.charge_amount,
});
}
},
StageSection::Swing => {
if !self.exhausted {
let damage = self.static_data.initial_damage
+ ((self.static_data.max_damage - self.static_data.initial_damage) as f32
* self.charge_amount) as u32;
let knockback = self.static_data.initial_knockback
+ (self.static_data.max_knockback - self.static_data.initial_knockback)
* self.charge_amount;
// Hit attempt
data.updater.insert(data.entity, Attacking {
base_damage: damage as u32,
base_heal: 0,
range: self.static_data.range,
max_angle: self.static_data.max_angle.to_radians(),
applied: false,
hit_count: 0,
knockback,
});
// Starts swinging
update.character = CharacterState::ChargedMelee(Data {
static_data: self.static_data,
stage_section: self.stage_section,
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
exhausted: true,
charge_amount: self.charge_amount,
});
} else if self.timer < self.static_data.swing_duration {
// Swings
update.character = CharacterState::ChargedMelee(Data {
static_data: self.static_data,
stage_section: self.stage_section,
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
exhausted: self.exhausted,
charge_amount: self.charge_amount,
});
} else {
// Transitions to recover
update.character = CharacterState::ChargedMelee(Data {
static_data: self.static_data,
stage_section: StageSection::Recover,
timer: Duration::default(),
exhausted: self.exhausted,
charge_amount: self.charge_amount,
});
}
},
StageSection::Recover => {
if self.timer < self.static_data.recover_duration {
// Recovers
update.character = CharacterState::ChargedMelee(Data {
static_data: self.static_data,
stage_section: self.stage_section,
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
exhausted: self.exhausted,
charge_amount: self.charge_amount,
});
} 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);
},
}
update
}
}

View File

@ -1,114 +1,197 @@
use crate::{
comp::{Attacking, CharacterState, StateUpdate},
states::utils::*,
states::utils::{StageSection, *},
sys::character_behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use vek::Vec3;
const LEAP_SPEED: f32 = 24.0;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data {
/// Separated out to condense update portions of character state
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StaticData {
/// How long the state is moving
pub movement_duration: Duration,
/// How long until state should deal damage
pub buildup_duration: Duration,
/// How long the weapon swings
pub swing_duration: Duration,
/// How long the state has until exiting
pub recover_duration: Duration,
/// Base damage
pub base_damage: u32,
/// Knockback
pub knockback: f32,
/// Max range
pub range: f32,
/// Max angle (45.0 will give you a 90.0 angle window)
pub max_angle: f32,
/// Affects how far forward the player leaps
pub forward_leap_strength: f32,
/// Affects how high the player leaps
pub vertical_leap_strength: 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
pub exhausted: bool,
pub initialize: bool,
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data);
if self.initialize {
update.vel.0 = *data.inputs.look_dir * 20.0;
if let Some(dir) = Vec3::from(data.inputs.look_dir.xy()).try_normalized() {
update.ori.0 = dir.into();
}
}
handle_move(data, &mut update, 0.3);
handle_jump(data, &mut update);
if self.movement_duration != Duration::default() {
// Jumping
update.vel.0 = Vec3::new(data.inputs.look_dir.x, data.inputs.look_dir.y, 8.0)
* ((self.movement_duration.as_millis() as f32) / 250.0)
+ (update.vel.0 * Vec3::new(2.0, 2.0, 0.0)
+ 0.25 * data.inputs.move_dir.try_normalized().unwrap_or_default())
.try_normalized()
.unwrap_or_default()
* LEAP_SPEED
* (1.0 - data.inputs.look_dir.z.abs());
match self.stage_section {
StageSection::Buildup => {
if self.timer < self.static_data.buildup_duration {
// Buildup
update.character = CharacterState::LeapMelee(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 {
// Transitions to leap portion of state
update.character = CharacterState::LeapMelee(Data {
static_data: self.static_data,
timer: Duration::default(),
stage_section: StageSection::Movement,
exhausted: self.exhausted,
});
}
},
StageSection::Movement => {
// Jumping
update.vel.0 = Vec3::new(
data.inputs.look_dir.x,
data.inputs.look_dir.y,
self.static_data.vertical_leap_strength,
) * 2.0
* (1.0
- self.timer.as_secs_f32()
/ self.static_data.movement_duration.as_secs_f32())
+ (update.vel.0 * Vec3::new(2.0, 2.0, 0.0)
+ 0.25 * data.inputs.move_dir.try_normalized().unwrap_or_default())
.try_normalized()
.unwrap_or_default()
* self.static_data.forward_leap_strength
* (1.0 - data.inputs.look_dir.z.abs());
update.character = CharacterState::LeapMelee(Data {
movement_duration: self
.movement_duration
.checked_sub(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
buildup_duration: self.buildup_duration,
recover_duration: self.recover_duration,
base_damage: self.base_damage,
exhausted: false,
initialize: false,
});
} else if self.buildup_duration != Duration::default() && !data.physics.on_ground {
// Falling
update.character = CharacterState::LeapMelee(Data {
movement_duration: Duration::default(),
buildup_duration: self
.buildup_duration
.checked_sub(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
recover_duration: self.recover_duration,
base_damage: self.base_damage,
exhausted: false,
initialize: false,
});
} else if !self.exhausted {
// Hit attempt
data.updater.insert(data.entity, Attacking {
base_damage: self.base_damage,
base_heal: 0,
range: 4.5,
max_angle: 360_f32.to_radians(),
applied: false,
hit_count: 0,
knockback: 25.0,
});
if self.timer < self.static_data.movement_duration {
// Movement duration
update.character = CharacterState::LeapMelee(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 {
// Transitions to swing portion of state
update.character = CharacterState::LeapMelee(Data {
static_data: self.static_data,
timer: Duration::default(),
stage_section: StageSection::Swing,
exhausted: self.exhausted,
});
}
},
StageSection::Swing => {
if self.timer < self.static_data.swing_duration {
// Swings weapons
update.character = CharacterState::LeapMelee(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 {
// Transitions to recover portion
update.character = CharacterState::LeapMelee(Data {
static_data: self.static_data,
timer: Duration::default(),
stage_section: StageSection::Recover,
exhausted: self.exhausted,
});
}
},
StageSection::Recover => {
if !data.physics.on_ground {
// Falls
update.character = CharacterState::LeapMelee(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 if !self.exhausted {
// Hit attempt
data.updater.insert(data.entity, Attacking {
base_damage: self.static_data.base_damage,
base_heal: 0,
range: self.static_data.range,
max_angle: self.static_data.max_angle.to_radians(),
applied: false,
hit_count: 0,
knockback: self.static_data.knockback,
});
update.character = CharacterState::LeapMelee(Data {
movement_duration: self.movement_duration,
buildup_duration: Duration::default(),
recover_duration: self.recover_duration,
base_damage: self.base_damage,
exhausted: true,
initialize: false,
});
} else if self.recover_duration != Duration::default() {
// Recovery
handle_move(data, &mut update, 0.7);
update.character = CharacterState::LeapMelee(Data {
movement_duration: self.movement_duration,
buildup_duration: self.buildup_duration,
recover_duration: self
.recover_duration
.checked_sub(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
base_damage: self.base_damage,
exhausted: true,
initialize: false,
});
} else {
// Done
update.character = CharacterState::Wielding;
// Make sure attack component is removed
data.updater.remove::<Attacking>(data.entity);
update.character = CharacterState::LeapMelee(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: true,
});
} else if self.timer < self.static_data.recover_duration {
// Recovers
update.character = CharacterState::LeapMelee(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);
},
}
update

View File

@ -3,6 +3,7 @@ pub mod basic_block;
pub mod basic_melee;
pub mod basic_ranged;
pub mod boost;
pub mod charged_melee;
pub mod charged_ranged;
pub mod climb;
pub mod combo_melee;
@ -14,6 +15,7 @@ pub mod glide_wield;
pub mod ground_shockwave;
pub mod idle;
pub mod leap_melee;
pub mod repeater_ranged;
pub mod roll;
pub mod sit;
pub mod sneak;

View File

@ -0,0 +1,207 @@
use crate::{
comp::{Body, CharacterState, Gravity, LightEmitter, Projectile, StateUpdate},
event::ServerEvent,
states::utils::{StageSection, *},
sys::character_behavior::*,
util::dir::*,
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use vek::Vec3;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
/// Separated out to condense update portions of character state
pub struct StaticData {
/// How long the state is in movement
pub movement_duration: Duration,
/// How long we've readied the weapon
pub buildup_duration: Duration,
/// How long the state is shooting
pub shoot_duration: Duration,
/// How long the state has until exiting
pub recover_duration: Duration,
/// Whether there should be a jump and how strong the leap is
pub leap: Option<f32>,
/// Projectile options
pub projectile: Projectile,
pub projectile_body: Body,
pub projectile_light: Option<LightEmitter>,
pub projectile_gravity: Option<Gravity>,
pub 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,
/// How many repetitions remaining
pub reps_remaining: u32,
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_move(data, &mut update, 1.0);
handle_jump(data, &mut update);
match self.stage_section {
StageSection::Movement => {
// Jumping
if let Some(leap_strength) = self.static_data.leap {
update.vel.0 = Vec3::new(
data.vel.0.x,
data.vel.0.y,
leap_strength
* (1.0
- self.timer.as_secs_f32()
/ self.static_data.movement_duration.as_secs_f32()),
);
}
if self.timer < self.static_data.movement_duration {
// Do movement
update.character = CharacterState::RepeaterRanged(Data {
static_data: self.static_data.clone(),
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
stage_section: self.stage_section,
reps_remaining: self.reps_remaining,
});
} else {
// Transition to buildup
update.character = CharacterState::RepeaterRanged(Data {
static_data: self.static_data.clone(),
timer: Duration::default(),
stage_section: StageSection::Buildup,
reps_remaining: self.reps_remaining,
});
}
},
StageSection::Buildup => {
// Aim gliding
if self.static_data.leap.is_some() {
update.vel.0 = Vec3::new(data.vel.0.x, data.vel.0.y, 0.0);
}
if self.timer < self.static_data.buildup_duration {
// Buildup to attack
update.character = CharacterState::RepeaterRanged(Data {
static_data: self.static_data.clone(),
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
stage_section: self.stage_section,
reps_remaining: self.reps_remaining,
});
} else {
// Transition to shoot
update.character = CharacterState::RepeaterRanged(Data {
static_data: self.static_data.clone(),
timer: Duration::default(),
stage_section: StageSection::Shoot,
reps_remaining: self.reps_remaining,
});
}
},
StageSection::Shoot => {
// Aim gliding
if self.static_data.leap.is_some() {
update.vel.0 = Vec3::new(data.vel.0.x, data.vel.0.y, 0.0);
}
if self.reps_remaining > 0 {
// Fire
let mut projectile = self.static_data.projectile.clone();
projectile.owner = Some(*data.uid);
update.server_events.push_front(ServerEvent::Shoot {
entity: data.entity,
// Provides slight variation to projectile direction
dir: Dir::from_unnormalized(Vec3::new(
data.inputs.look_dir[0]
+ (if self.reps_remaining % 2 == 0 {
self.reps_remaining as f32 / 400.0
} else {
-1.0 * self.reps_remaining as f32 / 400.0
}),
data.inputs.look_dir[1]
+ (if self.reps_remaining % 2 == 0 {
-1.0 * self.reps_remaining as f32 / 400.0
} else {
self.reps_remaining as f32 / 400.0
}),
data.inputs.look_dir[2],
))
.unwrap_or(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.projectile_speed,
});
// Shoot projectiles
update.character = CharacterState::RepeaterRanged(Data {
static_data: self.static_data.clone(),
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
stage_section: self.stage_section,
reps_remaining: self.reps_remaining - 1,
});
} else if self.timer < self.static_data.shoot_duration {
// Finish shooting
update.character = CharacterState::RepeaterRanged(Data {
static_data: self.static_data.clone(),
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
stage_section: self.stage_section,
reps_remaining: self.reps_remaining,
});
} else {
// Transition to recover
update.character = CharacterState::RepeaterRanged(Data {
static_data: self.static_data.clone(),
timer: Duration::default(),
stage_section: StageSection::Recover,
reps_remaining: self.reps_remaining,
});
}
},
StageSection::Recover => {
if self.static_data.leap.is_some() && data.physics.on_ground {
// Done
update.character = CharacterState::Wielding;
} else if self.timer < self.static_data.recover_duration {
// Recover from attack
update.character = CharacterState::RepeaterRanged(Data {
static_data: self.static_data.clone(),
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
stage_section: self.stage_section,
reps_remaining: self.reps_remaining,
});
} else {
// Done
update.character = CharacterState::Wielding;
}
},
_ => {
// If it somehow ends up in an incorrect stage section
update.character = CharacterState::Wielding;
},
}
update
}
}

View File

@ -107,7 +107,7 @@ pub fn forward_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32,
pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, rate: f32) {
// Set direction based on move direction
let ori_dir = if update.character.is_attack() | update.character.is_block() {
let ori_dir = if update.character.is_block() || update.character.is_attack() {
data.inputs.look_dir.xy()
} else if !data.inputs.move_dir.is_approx_zero() {
data.inputs.move_dir
@ -365,4 +365,6 @@ pub enum StageSection {
Recover,
Charge,
Cast,
Shoot,
Movement,
}

View File

@ -261,7 +261,9 @@ impl<'a> System<'a> for Sys {
CharacterState::DashMelee(data) => data.handle_event(&j, action),
CharacterState::LeapMelee(data) => data.handle_event(&j, action),
CharacterState::SpinMelee(data) => data.handle_event(&j, action),
CharacterState::ChargedMelee(data) => data.handle_event(&j, action),
CharacterState::ChargedRanged(data) => data.handle_event(&j, action),
CharacterState::RepeaterRanged(data) => data.handle_event(&j, action),
CharacterState::GroundShockwave(data) => data.handle_event(&j, action),
CharacterState::BasicBeam(data) => data.handle_event(&j, action),
};
@ -291,7 +293,9 @@ impl<'a> System<'a> for Sys {
CharacterState::DashMelee(data) => data.behavior(&j),
CharacterState::LeapMelee(data) => data.behavior(&j),
CharacterState::SpinMelee(data) => data.behavior(&j),
CharacterState::ChargedMelee(data) => data.behavior(&j),
CharacterState::ChargedRanged(data) => data.behavior(&j),
CharacterState::RepeaterRanged(data) => data.behavior(&j),
CharacterState::GroundShockwave(data) => data.behavior(&j),
CharacterState::BasicBeam(data) => data.behavior(&j),
};

View File

@ -112,7 +112,9 @@ impl<'a> System<'a> for Sys {
| CharacterState::SpinMelee { .. }
| CharacterState::ComboMelee { .. }
| CharacterState::BasicRanged { .. }
| CharacterState::ChargedMelee { .. }
| CharacterState::ChargedRanged { .. }
| CharacterState::RepeaterRanged { .. }
| CharacterState::GroundShockwave { .. }
| CharacterState::BasicBeam { .. } => {
if energy.get_unchecked().regen_rate != 0.0 {

View File

@ -1,5 +1,5 @@
mod color;
mod dir;
pub mod dir;
mod option;
pub mod userdata_dir;

View File

@ -8,7 +8,7 @@ version = "0.7.0"
name = "voxygen_anim"
# Uncomment to use animation hot reloading
# Note: this breaks `cargo test`
crate-type = ["lib", "cdylib"]
# crate-type = ["lib", "cdylib"]
[features]
be-dyn-lib = []

View File

@ -147,6 +147,22 @@ impl Animation for ChargeAnimation {
* Quaternion::rotation_z(stop * -0.6);
next.control.scale = Vec3::one();
},
Some(ToolKind::Hammer(_)) => {
next.l_hand.position = Vec3::new(-8.0, -2.0 + stop * -1.0, 13.0);
next.l_hand.orientation = Quaternion::rotation_x(2.1)
* Quaternion::rotation_y(0.7)
* Quaternion::rotation_z(-0.3);
next.l_hand.scale = Vec3::one() * 1.05;
next.r_hand.position = Vec3::new(-11.0, 2.0, 6.0);
next.r_hand.orientation = Quaternion::rotation_x(1.8)
* Quaternion::rotation_y(2.3)
* Quaternion::rotation_z(0.3);
next.r_hand.scale = Vec3::one() * 1.05;
next.main.position = Vec3::new(-12.0, 1.0, 4.0);
next.main.orientation = Quaternion::rotation_x(0.3)
* Quaternion::rotation_y(0.3)
* Quaternion::rotation_z(0.6);
},
_ => {},
}

View File

@ -0,0 +1,195 @@
use super::{
super::{vek::*, Animation},
CharacterSkeleton, SkeletonAttr,
};
use common::{
comp::item::{Hands, ToolKind},
states::utils::StageSection,
};
use std::f32::consts::PI;
pub struct ChargeswingAnimation;
impl Animation for ChargeswingAnimation {
type Dependency = (
Option<ToolKind>,
Option<ToolKind>,
Vec3<f32>,
f64,
Option<StageSection>,
);
type Skeleton = CharacterSkeleton;
#[cfg(feature = "use-dyn-lib")]
const UPDATE_FN: &'static [u8] = b"character_chargeswing\0";
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_chargeswing")]
#[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): Self::Dependency,
anim_time: f64,
rate: &mut f32,
skeleton_attr: &SkeletonAttr,
) -> Self::Skeleton {
*rate = 1.0;
let mut next = (*skeleton).clone();
let speed = Vec2::<f32>::from(velocity).magnitude();
let lab = 1.0;
let short = (((5.0)
/ (1.5 + 3.5 * ((anim_time as f32 * lab as f32 * 8.0).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * lab as f32 * 8.0).sin());
// end spin stuff
let movement = anim_time as f32 * 1.0;
let fire = (anim_time as f32 * 18.0 * lab as f32).sin();
let foothoril = (anim_time as f32 * 8.0 * lab as f32 + PI * 1.45).sin();
let foothorir = (anim_time as f32 * 8.0 * lab as f32 + PI * (0.45)).sin();
let footvertl = (anim_time as f32 * 8.0 * lab as f32).sin();
let footvertr = (anim_time as f32 * 8.0 * lab as f32 + PI).sin();
let footrotl = (((1.0)
/ (0.5
+ (0.5)
* ((anim_time as f32 * 8.0 * lab as f32 + PI * 1.4).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * 8.0 * lab as f32 + PI * 1.4).sin());
let footrotr = (((1.0)
/ (0.5
+ (0.5)
* ((anim_time as f32 * 8.0 * lab as f32 + PI * 0.4).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * 8.0 * lab as f32 + PI * 0.4).sin());
if let Some(ToolKind::Hammer(_)) = active_tool_kind {
next.l_hand.position = Vec3::new(-12.0, 0.0, 0.0);
next.l_hand.orientation = Quaternion::rotation_x(-0.0) * Quaternion::rotation_y(0.0);
next.l_hand.scale = Vec3::one() * 1.08;
next.r_hand.position = Vec3::new(2.0, 0.0, 0.0);
next.r_hand.orientation = Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
next.r_hand.scale = Vec3::one() * 1.06;
next.main.position = Vec3::new(0.0, 0.0, 0.0);
next.main.orientation = Quaternion::rotation_y(-1.57) * Quaternion::rotation_z(1.57);
next.control.position = Vec3::new(6.0, 7.0, 1.0);
next.control.orientation = Quaternion::rotation_x(0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.control.scale = Vec3::one();
if let Some(stage_section) = stage_section {
match stage_section {
StageSection::Charge => {
next.control.position = Vec3::new(
6.0 + (movement * -4.0).max(-8.0),
7.0 + (movement * 2.0).min(2.0),
1.0,
);
next.control.orientation = Quaternion::rotation_x(0.3)
* Quaternion::rotation_y(
0.0 + (movement * 0.7).min(0.7)
+ fire * 0.1 * (anim_time as f32).min(2.0),
)
* Quaternion::rotation_z(0.0 + (movement * 0.2).min(0.5));
next.chest.position =
Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1);
next.chest.orientation =
Quaternion::rotation_z((movement * 2.0).min(PI / 2.0));
next.belt.orientation =
Quaternion::rotation_z((short * 0.08 + movement * -1.0).max(-PI / 5.0));
next.shorts.orientation =
Quaternion::rotation_z((short * 0.15 + movement * -1.0).max(-PI / 4.0));
next.head.position = Vec3::new(
0.0,
skeleton_attr.head.0 - 2.0 + (movement * 2.0).min(2.0),
skeleton_attr.head.1,
);
next.head.orientation =
Quaternion::rotation_z((movement * -1.8).max(PI / -2.0));
next.belt.orientation = Quaternion::rotation_z(short * 0.05);
next.shorts.orientation = Quaternion::rotation_z(short * 0.15);
if speed > 0.5 {
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0,
skeleton_attr.foot.1 + foothoril * -2.5 - 3.5,
skeleton_attr.foot.2 + ((footvertl * -1.2).max(-1.0)),
);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0,
skeleton_attr.foot.1 + foothorir * -2.5 + 6.0,
skeleton_attr.foot.2 + ((footvertr * -1.2).max(-1.0)),
);
next.l_foot.orientation =
Quaternion::rotation_x(-0.4 + footrotl * -0.2)
* Quaternion::rotation_z((movement * 0.5).min(0.5));
next.l_foot.scale = Vec3::one();
next.r_foot.orientation =
Quaternion::rotation_x(-0.4 + footrotr * -0.2)
* Quaternion::rotation_z((movement * 0.5).min(0.5));
} else {
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0,
skeleton_attr.foot.1 - 5.0,
skeleton_attr.foot.2,
);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0,
skeleton_attr.foot.1 + 7.0,
skeleton_attr.foot.2,
);
next.l_foot.orientation =
Quaternion::rotation_x(-0.2) * Quaternion::rotation_z(0.5);
next.r_foot.orientation =
Quaternion::rotation_x(0.2) * Quaternion::rotation_z(0.5);
};
},
StageSection::Swing => {
next.chest.orientation = Quaternion::rotation_z(-0.5);
next.control.position = Vec3::new(6.0, 7.0, 1.0 + 3.0);
next.control.orientation = Quaternion::rotation_x(PI / 2.0)
* Quaternion::rotation_y(-1.6)
* Quaternion::rotation_z(0.3 - movement * 2.5);
next.head.orientation = Quaternion::rotation_z(0.8);
next.l_hand.position = Vec3::new(-3.0, 0.0, 0.0);
},
StageSection::Recover => {
next.chest.orientation = Quaternion::rotation_z(-0.5 + movement * 0.5);
next.control.position = Vec3::new(6.0, 7.0, 1.0 + 3.0 + movement * -3.0);
next.control.orientation = Quaternion::rotation_x(PI / 2.0)
* Quaternion::rotation_y(-1.6 + movement * 1.6)
* Quaternion::rotation_z(-2.2 + movement * 2.2);
next.head.orientation = Quaternion::rotation_z(0.8 + movement * -0.8);
next.l_hand.position = Vec3::new(-3.0 + movement * -9.0, 0.0, 0.0);
},
_ => {},
}
}
}
next.second.scale = match (
active_tool_kind.map(|tk| tk.hands()),
second_tool_kind.map(|tk| tk.hands()),
) {
(Some(Hands::OneHand), Some(Hands::OneHand)) => Vec3::one(),
(_, _) => Vec3::zero(),
};
//next.torso.position = Vec3::new(0.0, 0.0, 0.0) * skeleton_attr.scaler;
//next.torso.orientation = Quaternion::rotation_z(0.0);
//next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next
}
}

View File

@ -1,12 +1,22 @@
use super::{super::Animation, CharacterSkeleton, SkeletonAttr};
use common::comp::item::{Hands, ToolKind};
/* use std::f32::consts::PI; */
use super::super::vek::*;
use super::{
super::{vek::*, Animation},
CharacterSkeleton, SkeletonAttr,
};
use common::{
comp::item::{Hands, ToolKind},
states::utils::StageSection,
};
use std::f32::consts::PI;
pub struct LeapAnimation;
impl Animation for LeapAnimation {
type Dependency = (Option<ToolKind>, Option<ToolKind>, Vec3<f32>, f64);
type Dependency = (
Option<ToolKind>,
Option<ToolKind>,
Vec3<f32>,
f64,
Option<StageSection>,
);
type Skeleton = CharacterSkeleton;
#[cfg(feature = "use-dyn-lib")]
@ -16,7 +26,7 @@ impl Animation for LeapAnimation {
#[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): Self::Dependency,
(active_tool_kind, second_tool_kind, _velocity, _global_time, stage_section): Self::Dependency,
anim_time: f64,
rate: &mut f32,
skeleton_attr: &SkeletonAttr,
@ -24,86 +34,306 @@ impl Animation for LeapAnimation {
*rate = 1.0;
let mut next = (*skeleton).clone();
let lab = 1.0;
let slowersmooth = (anim_time as f32 * lab as f32 * 4.0).sin();
let slower = (((1.0)
/ (0.0001 + 0.999 * ((anim_time as f32 * lab as f32 * 4.0).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * lab as f32 * 4.0).sin());
let movement = (anim_time as f32 * 1.0).min(1.0);
if let Some(ToolKind::Hammer(_)) = active_tool_kind {
next.l_hand.position = Vec3::new(-12.0, 0.0, 0.0);
next.l_hand.orientation = Quaternion::rotation_x(-0.0) * Quaternion::rotation_y(0.0);
next.l_hand.orientation = Quaternion::rotation_x(PI) * Quaternion::rotation_y(0.0);
next.l_hand.scale = Vec3::one() * 1.08;
next.r_hand.position = Vec3::new(3.0, 0.0, 0.0);
next.r_hand.orientation = Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
next.r_hand.position = Vec3::new(2.0, 0.0, 0.0);
next.r_hand.orientation = Quaternion::rotation_x(PI) * Quaternion::rotation_y(0.0);
next.r_hand.scale = Vec3::one() * 1.06;
next.main.position = Vec3::new(0.0, 0.0, 0.0);
next.main.orientation = Quaternion::rotation_x(0.0)
* Quaternion::rotation_y(-1.57)
* Quaternion::rotation_z(1.57);
next.main.orientation = Quaternion::rotation_y(-1.57) * Quaternion::rotation_z(1.57);
next.head.position = Vec3::new(
0.0,
-2.0 + skeleton_attr.head.0 + slower * -1.0,
skeleton_attr.head.1,
);
next.head.orientation = Quaternion::rotation_z(slower * 0.05)
* Quaternion::rotation_x((slowersmooth * -0.25 + slower * 0.55).max(-0.2))
* Quaternion::rotation_y(slower * 0.05);
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
next.chest.position = Vec3::new(0.0, 0.0, 7.0);
next.chest.orientation = Quaternion::rotation_z(slower * 0.08 + slowersmooth * 0.15)
* Quaternion::rotation_x(-0.3 + slower * 0.45 + slowersmooth * 0.26)
* Quaternion::rotation_y(slower * 0.18 + slowersmooth * 0.15);
next.belt.position = Vec3::new(0.0, 0.0, -2.0 + slower * -0.7);
next.belt.orientation = Quaternion::rotation_z(slower * -0.16 + slowersmooth * -0.12)
* Quaternion::rotation_x(0.0 + slower * -0.06)
* Quaternion::rotation_y(slower * -0.05);
next.shorts.position = Vec3::new(0.0, 0.0, -5.0 + slower * -0.7);
next.shorts.orientation = Quaternion::rotation_z(slower * -0.08 + slowersmooth * -0.08)
* Quaternion::rotation_x(0.0 + slower * -0.08 + slowersmooth * -0.08)
* Quaternion::rotation_y(slower * -0.07);
next.lantern.orientation =
Quaternion::rotation_x(slower * -0.7 + 0.4) * Quaternion::rotation_y(slower * 0.4);
next.hold.scale = Vec3::one() * 0.0;
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0,
slower * 3.0 + slowersmooth * -6.0 - 2.0,
skeleton_attr.foot.2,
);
next.l_foot.orientation =
Quaternion::rotation_x(slower * -0.2 + slowersmooth * -0.3 - 0.2);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0,
slower * 2.0 + slowersmooth * -4.0 - 1.0,
-2.0 + skeleton_attr.foot.2,
);
next.r_foot.orientation =
Quaternion::rotation_x(slower * -0.4 + slowersmooth * -0.6 - 1.0);
next.control.scale = Vec3::one();
next.control.position = Vec3::new(-7.0, 7.0, 1.0);
next.control.orientation = Quaternion::rotation_x(-0.7 + slower * 1.5)
next.control.position = Vec3::new(6.0, 7.0, 1.0);
next.control.orientation = Quaternion::rotation_x(0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(1.4 + slowersmooth * -0.4 + slower * 0.2);
* Quaternion::rotation_z(0.0);
next.control.scale = Vec3::one();
next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1);
if let Some(stage_section) = stage_section {
match stage_section {
StageSection::Buildup => {
next.control.position = Vec3::new(6.0, 7.0, 1.0);
next.control.orientation = Quaternion::rotation_x(0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(movement * 0.5);
next.chest.orientation = Quaternion::rotation_x(movement * 0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(movement * 0.5);
next.head.orientation = Quaternion::rotation_x(0.0)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(movement * -0.4);
},
StageSection::Movement => {
next.control.position = Vec3::new(
6.0 + movement * -10.0,
7.0 + movement * 5.0,
1.0 + movement * 5.0,
);
next.control.orientation = Quaternion::rotation_x(0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.5 + movement * 0.5);
next.chest.orientation = Quaternion::rotation_x(0.3 + movement * 0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.5 + movement * 0.2);
next.head.orientation = Quaternion::rotation_x(0.0)
* Quaternion::rotation_y(movement * -0.1)
* Quaternion::rotation_z(-0.4 + movement * -0.2);
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0,
skeleton_attr.foot.1 - 5.0,
skeleton_attr.foot.2,
);
next.l_foot.orientation = Quaternion::rotation_x(-0.8);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0,
skeleton_attr.foot.1 + 8.0,
skeleton_attr.foot.2 + 5.0,
);
next.r_foot.orientation = Quaternion::rotation_x(0.9);
},
StageSection::Swing => {
next.control.position =
Vec3::new(-4.0, 12.0 + movement * 5.0, 6.0 + movement * -7.0);
next.control.orientation = Quaternion::rotation_x(0.3 + movement * -3.0)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(1.0 + movement * 0.5);
next.chest.orientation = Quaternion::rotation_x(0.6 + movement * -0.9)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.7 + movement * -0.7);
next.head.orientation = Quaternion::rotation_x(movement * 0.2)
* Quaternion::rotation_y(-0.1)
* Quaternion::rotation_z(-0.6 + movement * 0.6);
next.l_hand.position = Vec3::new(-12.0 + movement * 10.0, 0.0, 0.0);
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0,
skeleton_attr.foot.1 + 8.0,
skeleton_attr.foot.2 - 5.0,
);
next.l_foot.orientation = Quaternion::rotation_x(0.9);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0,
skeleton_attr.foot.1 - 5.0,
skeleton_attr.foot.2,
);
next.r_foot.orientation = Quaternion::rotation_x(-0.8);
},
StageSection::Recover => {
next.control.position = Vec3::new(-4.0, 17.0, -1.0);
next.control.orientation = Quaternion::rotation_x(-2.7)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(1.5);
next.chest.orientation = Quaternion::rotation_x(-0.3 + movement * 0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.head.orientation = Quaternion::rotation_x(0.2)
* Quaternion::rotation_y(-0.1)
* Quaternion::rotation_z(0.0);
next.l_hand.position = Vec3::new(-2.0, 0.0, 0.0);
},
_ => {},
}
}
} else if let Some(ToolKind::Axe(_)) = active_tool_kind {
next.l_hand.position = Vec3::new(-0.5, 0.0, 4.0);
next.l_hand.orientation = Quaternion::rotation_x(PI / 2.0)
* Quaternion::rotation_z(0.0)
* Quaternion::rotation_y(0.0);
next.l_hand.scale = Vec3::one() * 1.08;
next.r_hand.position = Vec3::new(0.5, 0.0, -2.5);
next.r_hand.orientation = Quaternion::rotation_x(PI / 2.0)
* Quaternion::rotation_z(0.0)
* Quaternion::rotation_y(0.0);
next.r_hand.scale = Vec3::one() * 1.06;
next.main.position = Vec3::new(-0.0, -2.0, -1.0);
next.main.orientation = Quaternion::rotation_x(0.0)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.control.position = Vec3::new(-3.0, 11.0, 3.0);
next.control.orientation = Quaternion::rotation_x(1.8)
* Quaternion::rotation_y(-0.5)
* Quaternion::rotation_z(PI - 0.2);
next.control.scale = Vec3::one();
next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1);
if let Some(stage_section) = stage_section {
match stage_section {
StageSection::Buildup => {
next.control.position = Vec3::new(
-3.0 + movement * 3.0,
11.0 + movement * 1.0,
3.0 + movement * 12.0,
);
next.control.orientation = Quaternion::rotation_x(1.8 + movement * -1.0)
* Quaternion::rotation_y(-0.5 + movement * 0.5)
* Quaternion::rotation_z(PI + 0.2 - movement * 0.2);
next.chest.orientation = Quaternion::rotation_x(movement * -0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(movement * 0.5);
next.head.orientation = Quaternion::rotation_x(0.0 + movement * -0.4);
next.l_foot.position = Vec3::new(
skeleton_attr.foot.0,
skeleton_attr.foot.1,
skeleton_attr.foot.2 - 8.0,
);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0,
skeleton_attr.foot.1,
skeleton_attr.foot.2 - 8.0,
);
next.l_foot.orientation = Quaternion::rotation_x(movement * 0.9);
next.r_foot.orientation = Quaternion::rotation_x(movement * 0.9);
next.belt.orientation = Quaternion::rotation_x(movement * 0.22);
next.shorts.orientation = Quaternion::rotation_x(movement * 0.3);
next.chest.position =
Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1 - 8.0);
next.torso.position =
Vec3::new(0.0, 0.0, 0.0 + 8.0) * skeleton_attr.scaler / 11.0;
},
StageSection::Movement => {
next.control.position = Vec3::new(
0.0, 12.0, //11
15.0,
);
next.chest.position =
Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1 - 8.0);
next.torso.position = Vec3::new(0.0, 0.0, 0.0 + 8.0) * skeleton_attr.scaler;
next.control.orientation = Quaternion::rotation_x(0.8 + movement * -0.5)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(PI);
next.torso.orientation = Quaternion::rotation_x(-0.3 + movement * 6.0)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.head.orientation = Quaternion::rotation_x(-0.4 + movement * 0.4);
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0,
skeleton_attr.foot.1 + movement * 4.0,
skeleton_attr.foot.2 - 8.0 + movement * 3.0,
);
next.l_foot.orientation = Quaternion::rotation_x(0.9);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0,
skeleton_attr.foot.1 + movement * 4.0,
skeleton_attr.foot.2 - 8.0 + movement * 3.0,
);
next.r_foot.orientation = Quaternion::rotation_x(0.9);
next.chest.position =
Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1 - 8.0);
next.torso.position =
Vec3::new(0.0, 0.0, 0.0 + 8.0) * skeleton_attr.scaler / 11.0;
next.torso.orientation = Quaternion::rotation_x(movement * -1.8 * PI);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.belt.orientation = Quaternion::rotation_x(0.22 + movement * 0.1);
next.shorts.orientation = Quaternion::rotation_x(0.3 + movement * 0.1);
next.chest.position =
Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1 - 8.0);
next.torso.position =
Vec3::new(0.0, 0.0, 0.0 + 8.0) * skeleton_attr.scaler / 11.0;
},
StageSection::Swing => {
next.control.position =
Vec3::new(0.0, 12.0 + movement * 3.0, 15.0 + movement * -15.0);
next.control.orientation = Quaternion::rotation_x(0.3 + movement * -1.0)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(PI);
next.head.orientation = Quaternion::rotation_x(movement * 0.2);
next.l_hand.position = Vec3::new(-0.5, 0.0, 4.0);
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0,
skeleton_attr.foot.1 + 4.0 + movement * -8.0,
skeleton_attr.foot.2 - 5.0 + movement * -3.0,
);
next.l_foot.orientation = Quaternion::rotation_x(0.9 - movement * 1.8);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0,
skeleton_attr.foot.1 + 4.0 + movement * -8.0,
skeleton_attr.foot.2 - 5.0 + movement * -3.0,
);
next.r_foot.orientation = Quaternion::rotation_x(0.9 - movement * 1.8);
next.torso.orientation =
Quaternion::rotation_x(-1.9 * PI - movement * 0.2 * PI);
next.chest.position =
Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1 - 8.0);
next.torso.position =
Vec3::new(0.0, 0.0, 0.0 + 8.0) * skeleton_attr.scaler / 11.0;
},
StageSection::Recover => {
next.control.position = Vec3::new(0.0, 15.0, 0.0);
next.control.orientation = Quaternion::rotation_x(-0.7)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(PI);
next.head.orientation = Quaternion::rotation_x(0.2);
next.l_hand.position = Vec3::new(-0.5, 0.0, 4.0);
next.chest.position =
Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1 - 8.0);
next.torso.position =
Vec3::new(0.0, 0.0, 0.0 + 8.0) * skeleton_attr.scaler / 11.0;
next.torso.orientation =
Quaternion::rotation_x(-6.7 + movement * -0.1 * PI);
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0,
skeleton_attr.foot.1 - 4.0,
skeleton_attr.foot.2 - 8.0,
);
next.l_foot.orientation = Quaternion::rotation_x(-0.9);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0,
skeleton_attr.foot.1 - 4.0,
skeleton_attr.foot.2 - 8.0,
);
next.r_foot.orientation = Quaternion::rotation_x(-0.9);
},
_ => {},
}
}
}
next.lantern.position = Vec3::new(
skeleton_attr.lantern.0,
skeleton_attr.lantern.1,
skeleton_attr.lantern.2,
);
next.glider.position = Vec3::new(0.0, 0.0, 10.0);
next.glider.scale = Vec3::one() * 0.0;
next.l_control.scale = Vec3::one();
next.r_control.scale = Vec3::one();
//next.lantern.position = Vec3::new(
// skeleton_attr.lantern.0,
// skeleton_attr.lantern.1,
// skeleton_attr.lantern.2,
//);
//next.glider.position = Vec3::new(0.0, 0.0, 10.0);
//next.glider.scale = Vec3::one() * 0.0;
//next.l_control.scale = Vec3::one();
//next.r_control.scale = Vec3::one();
next.second.scale = match (
active_tool_kind.map(|tk| tk.hands()),
@ -113,9 +343,9 @@ impl Animation for LeapAnimation {
(_, _) => Vec3::zero(),
};
next.torso.position = Vec3::new(0.0, 0.0, 0.0) * skeleton_attr.scaler;
next.torso.orientation = Quaternion::rotation_z(0.0);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
//next.torso.position = Vec3::new(0.0, 0.0, 0.0) * skeleton_attr.scaler;
//next.torso.orientation = Quaternion::rotation_z(0.0);
//next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next
}
}

View File

@ -3,6 +3,7 @@ pub mod beta;
pub mod block;
pub mod blockidle;
pub mod charge;
pub mod chargeswing;
pub mod climb;
pub mod dance;
pub mod dash;
@ -12,6 +13,7 @@ pub mod gliding;
pub mod idle;
pub mod jump;
pub mod leapmelee;
pub mod repeater;
pub mod roll;
pub mod run;
pub mod shoot;
@ -27,13 +29,14 @@ pub mod wield;
// Reexports
pub use self::{
alpha::AlphaAnimation, beta::BetaAnimation, block::BlockAnimation,
blockidle::BlockIdleAnimation, charge::ChargeAnimation, climb::ClimbAnimation,
dance::DanceAnimation, dash::DashAnimation, equip::EquipAnimation,
blockidle::BlockIdleAnimation, charge::ChargeAnimation, chargeswing::ChargeswingAnimation,
climb::ClimbAnimation, dance::DanceAnimation, dash::DashAnimation, equip::EquipAnimation,
glidewield::GlideWieldAnimation, gliding::GlidingAnimation, idle::IdleAnimation,
jump::JumpAnimation, leapmelee::LeapAnimation, roll::RollAnimation, run::RunAnimation,
shoot::ShootAnimation, sit::SitAnimation, sneak::SneakAnimation, spin::SpinAnimation,
spinmelee::SpinMeleeAnimation, stand::StandAnimation, swim::SwimAnimation,
swimwield::SwimWieldAnimation, wield::WieldAnimation,
jump::JumpAnimation, leapmelee::LeapAnimation, repeater::RepeaterAnimation,
roll::RollAnimation, run::RunAnimation, shoot::ShootAnimation, sit::SitAnimation,
sneak::SneakAnimation, spin::SpinAnimation, spinmelee::SpinMeleeAnimation,
stand::StandAnimation, swim::SwimAnimation, swimwield::SwimWieldAnimation,
wield::WieldAnimation,
};
use super::{make_bone, vek::*, FigureBoneData, Skeleton};

View File

@ -0,0 +1,198 @@
use super::{
super::{vek::*, Animation},
CharacterSkeleton, SkeletonAttr,
};
use common::{
comp::item::{Hands, ToolKind},
states::utils::StageSection,
};
pub struct RepeaterAnimation;
impl Animation for RepeaterAnimation {
type Dependency = (
Option<ToolKind>,
Option<ToolKind>,
Vec3<f32>,
f64,
Option<StageSection>,
);
type Skeleton = CharacterSkeleton;
#[cfg(feature = "use-dyn-lib")]
const UPDATE_FN: &'static [u8] = b"character_repeater\0";
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_repeater")]
#[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): Self::Dependency,
anim_time: f64,
rate: &mut f32,
skeleton_attr: &SkeletonAttr,
) -> Self::Skeleton {
*rate = 1.0;
let mut next = (*skeleton).clone();
let lab = 1.0;
// end spin stuff
let movement = (anim_time as f32 * 1.0).min(1.0);
let fire = (anim_time as f32 * 18.0 * lab as f32).sin();
if let Some(ToolKind::Bow(_)) = active_tool_kind {
next.l_hand.position = Vec3::new(2.0, 1.5, 0.0);
next.l_hand.orientation = Quaternion::rotation_x(1.20)
* Quaternion::rotation_y(-0.6)
* Quaternion::rotation_z(-0.3);
next.l_hand.scale = Vec3::one() * 1.05;
next.r_hand.position = Vec3::new(5.9, 4.5, -5.0);
next.r_hand.orientation = Quaternion::rotation_x(1.20)
* Quaternion::rotation_y(-0.6)
* Quaternion::rotation_z(-0.3);
next.r_hand.scale = Vec3::one() * 1.05;
next.main.position = Vec3::new(3.0, 2.0, -13.0);
next.main.orientation = Quaternion::rotation_x(-0.3)
* Quaternion::rotation_y(0.3)
* Quaternion::rotation_z(-0.6);
next.hold.position = Vec3::new(1.2, -1.0, -5.2);
next.hold.orientation = Quaternion::rotation_x(-1.7)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(-0.1);
next.hold.scale = Vec3::one() * 1.0;
next.control.position = Vec3::new(-7.0, 6.0, 6.0);
next.control.orientation = Quaternion::rotation_x(0.0) * Quaternion::rotation_z(0.0);
next.control.scale = Vec3::one();
if let Some(stage_section) = stage_section {
match stage_section {
StageSection::Movement => {
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0 + movement * -0.75 - 0.75,
skeleton_attr.foot.1 + movement * 4.0 + 4.0,
skeleton_attr.foot.2 + movement * 2.5 + 2.5,
);
next.l_foot.orientation = Quaternion::rotation_x(movement * 0.6 + 0.6)
* Quaternion::rotation_z(movement * 0.3 + 0.3);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0 + movement * 0.75 + 0.75,
skeleton_attr.foot.1 + movement * 4.0 + 4.0,
skeleton_attr.foot.2 + movement * 2.5 + 2.5,
);
next.r_foot.orientation = Quaternion::rotation_x(movement * 0.6 + 0.6)
* Quaternion::rotation_z(movement * -0.3 - 0.3);
next.shorts.position = Vec3::new(
0.0,
skeleton_attr.shorts.0 + movement * 4.0,
skeleton_attr.shorts.1 + movement * 1.0,
);
next.shorts.orientation = Quaternion::rotation_x(movement * 0.6);
next.belt.position = Vec3::new(
0.0,
skeleton_attr.belt.0 + movement * 2.0,
skeleton_attr.belt.1,
);
next.belt.orientation = Quaternion::rotation_x(movement * 0.2);
next.control.position = Vec3::new(
-7.0 + movement * 5.0,
6.0 + movement * 3.0,
6.0 + movement * 1.0,
);
next.control.orientation = Quaternion::rotation_x(movement * 0.4)
* Quaternion::rotation_y(movement * 0.8);
next.head.orientation = Quaternion::rotation_y(movement * 0.15);
next.torso.orientation = Quaternion::rotation_x(movement * 0.1)
},
StageSection::Buildup => {
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0 - 1.5,
skeleton_attr.foot.1 + 8.0,
skeleton_attr.foot.2 + 5.0,
);
next.l_foot.orientation = Quaternion::rotation_x(1.2 + movement * -0.2)
* Quaternion::rotation_z(0.6);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0 + 1.5,
skeleton_attr.foot.1 + 8.0,
skeleton_attr.foot.2 + 5.0,
);
next.r_foot.orientation = Quaternion::rotation_x(1.2 + movement * -0.2)
* Quaternion::rotation_z(-0.6);
next.shorts.position = Vec3::new(
0.0,
skeleton_attr.shorts.0 + 4.0,
skeleton_attr.shorts.1 + 1.0,
);
next.shorts.orientation = Quaternion::rotation_x(0.6);
next.belt.position =
Vec3::new(0.0, skeleton_attr.belt.0 + 2.0, skeleton_attr.belt.1);
next.belt.orientation = Quaternion::rotation_x(0.2);
next.control.position = Vec3::new(-2.0, 9.0, 7.0);
next.control.orientation =
Quaternion::rotation_x(0.4) * Quaternion::rotation_y(0.8);
next.head.orientation = Quaternion::rotation_y(0.15 + movement * 0.05);
next.torso.orientation = Quaternion::rotation_x(0.1 + movement * 0.1);
},
StageSection::Shoot => {
next.l_foot.position = Vec3::new(
-skeleton_attr.foot.0 - 1.5,
skeleton_attr.foot.1 + 8.0,
skeleton_attr.foot.2 + 5.0,
);
next.l_foot.orientation =
Quaternion::rotation_x(1.0) * Quaternion::rotation_z(0.6);
next.r_foot.position = Vec3::new(
skeleton_attr.foot.0 + 1.5,
skeleton_attr.foot.1 + 8.0,
skeleton_attr.foot.2 + 5.0,
);
next.r_foot.orientation =
Quaternion::rotation_x(1.0) * Quaternion::rotation_z(-0.6);
next.shorts.position = Vec3::new(
0.0,
skeleton_attr.shorts.0 + 4.0,
skeleton_attr.shorts.1 + 1.0,
);
next.shorts.orientation = Quaternion::rotation_x(0.6);
next.belt.position =
Vec3::new(0.0, skeleton_attr.belt.0 + 2.0, skeleton_attr.belt.1);
next.belt.orientation = Quaternion::rotation_x(0.2);
next.control.position = Vec3::new(-2.0, 9.0, 7.0);
next.control.orientation =
Quaternion::rotation_x(0.4) * Quaternion::rotation_y(0.8);
next.head.orientation = Quaternion::rotation_y(0.2);
next.torso.orientation = Quaternion::rotation_x(0.2 + movement * 0.15);
next.l_hand.position =
Vec3::new(2.0 + fire * -6.0 - 3.0, 1.5 + fire * -6.0 - 3.0, 0.0);
next.l_hand.orientation = Quaternion::rotation_x(1.20)
* Quaternion::rotation_y(-0.6)
* Quaternion::rotation_z(-0.3);
next.hold.scale = Vec3::one() * 0.0;
},
StageSection::Recover => {},
_ => {},
}
}
}
next.second.scale = match (
active_tool_kind.map(|tk| tk.hands()),
second_tool_kind.map(|tk| tk.hands()),
) {
(Some(Hands::OneHand), Some(Hands::OneHand)) => Vec3::one(),
(_, _) => Vec3::zero(),
};
//next.torso.position = Vec3::new(0.0, 0.0, 0.0) * skeleton_attr.scaler;
//next.torso.orientation = Quaternion::rotation_z(0.0);
//next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next
}
}

View File

@ -81,6 +81,9 @@ impl State {
ToolKind::Staff(_) => true,
ToolKind::Debug(kind) => kind == "Boost",
ToolKind::Sword(_) => true,
ToolKind::Hammer(_) => true,
ToolKind::Axe(_) => true,
ToolKind::Bow(_) => true,
_ => false,
}
} else {

View File

@ -140,7 +140,7 @@ image_ids! {
flyingrod_m1: "voxygen.element.icons.debug_wand_m1",
flyingrod_m2: "voxygen.element.icons.debug_wand_m2",
sword_pierce: "voxygen.element.icons.skill_sword_pierce",
hammerleap: "voxygen.element.icons.skill_hammerleap",
hammergolf: "voxygen.element.icons.skill_hammergolf",
axespin: "voxygen.element.icons.skill_axespin",
// Skillbar
@ -277,6 +277,9 @@ image_ids! {
heal_0: "voxygen.element.icons.heal_0",
sword_whirlwind: "voxygen.element.icons.sword_whirlwind",
heal_bomb: "voxygen.element.icons.heal_bomb",
hammerleap: "voxygen.element.icons.skill_hammerleap",
skill_axe_leap_slash: "voxygen.element.icons.skill_axe_leap_slash",
skill_bow_jump_burst: "voxygen.element.icons.skill_bow_jump_burst",
// Buttons
button: "voxygen.element.buttons.button",

View File

@ -696,7 +696,7 @@ impl<'a> Widget for Skillbar<'a> {
Some(ToolKind::Sword(_)) => self.imgs.twohsword_m2,
Some(ToolKind::Dagger(_)) => self.imgs.onehdagger_m2,
Some(ToolKind::Shield(_)) => self.imgs.onehshield_m2,
Some(ToolKind::Hammer(_)) => self.imgs.hammerleap,
Some(ToolKind::Hammer(_)) => self.imgs.hammergolf,
Some(ToolKind::Axe(_)) => self.imgs.axespin,
Some(ToolKind::Bow(_)) => self.imgs.bow_m2,
Some(ToolKind::Sceptre(_)) => self.imgs.heal_bomb,
@ -724,6 +724,13 @@ impl<'a> Widget for Skillbar<'a> {
Color::Rgba(0.3, 0.3, 0.3, 0.8)
}
},
Some(ToolKind::Axe(_)) => {
if self.energy.current() as f64 >= 100.0 {
Color::Rgba(1.0, 1.0, 1.0, 1.0)
} else {
Color::Rgba(0.3, 0.3, 0.3, 0.8)
}
},
_ => Color::Rgba(1.0, 1.0, 1.0, 1.0),
})
.set(state.ids.m2_content, ui);
@ -785,6 +792,14 @@ impl<'a> Widget for Skillbar<'a> {
.map(|i| i.item.kind())
.and_then(|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((
"Firebomb",
"\nWhirls a big fireball into the air. \nExplodes the ground \
@ -794,6 +809,10 @@ impl<'a> Widget for Skillbar<'a> {
"Whirlwind",
"\nMove forward while spinning with \n your sword.",
)),
ToolKind::Bow(_) => Some((
"Burst",
"\nLaunches a burst of arrows at the top \nof a running leap.",
)),
ToolKind::Debug(kind) => match kind.as_ref() {
"Boost" => Some((
"Possessing Arrow",

View File

@ -85,6 +85,9 @@ pub enum HotbarImage {
Fireball,
SnakeArrow,
SwordWhirlwind,
HammerLeap,
AxeLeapSlash,
BowJumpBurst,
}
type HotbarSource<'a> = (&'a hotbar::State, &'a Inventory, &'a Loadout, &'a Energy);
@ -110,6 +113,9 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
match kind {
ItemKind::Tool(Tool { kind, .. }) => match kind {
ToolKind::Staff(_) => Some(HotbarImage::Fireball),
ToolKind::Hammer(_) => Some(HotbarImage::HammerLeap),
ToolKind::Axe(_) => Some(HotbarImage::AxeLeapSlash),
ToolKind::Bow(_) => Some(HotbarImage::BowJumpBurst),
ToolKind::Debug(kind) => match kind.as_ref() {
"Boost" => Some(HotbarImage::SnakeArrow),
_ => None,
@ -119,11 +125,27 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
},
_ => None,
}
.map(|image_key| {
(
.map(|image_key| match image_key {
HotbarImage::Fireball => (
image_key,
(energy.current() < 500).then_some(Color::Rgba(0.3, 0.3, 0.3, 0.8)),
)
(energy.current() < 450).then_some(Color::Rgba(0.3, 0.3, 0.3, 0.8)),
),
HotbarImage::HammerLeap => (
image_key,
(energy.current() < 700).then_some(Color::Rgba(0.3, 0.3, 0.3, 0.8)),
),
HotbarImage::AxeLeapSlash => (
image_key,
(energy.current() < 450).then_some(Color::Rgba(0.3, 0.3, 0.3, 0.8)),
),
HotbarImage::BowJumpBurst => (
image_key,
(energy.current() < 450).then_some(Color::Rgba(0.3, 0.3, 0.3, 0.8)),
),
_ => (
image_key,
(energy.current() < 1000).then_some(Color::Rgba(1.0, 1.0, 1.0, 1.0)),
),
})
}),
})
@ -146,6 +168,9 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
HotbarImage::SnakeArrow => imgs.snake_arrow_0,
HotbarImage::Fireball => imgs.fire_spell_1,
HotbarImage::SwordWhirlwind => imgs.sword_whirlwind,
HotbarImage::HammerLeap => imgs.hammerleap,
HotbarImage::AxeLeapSlash => imgs.skill_axe_leap_slash,
HotbarImage::BowJumpBurst => imgs.skill_bow_jump_burst,
}
}
}

View File

@ -848,6 +848,36 @@ impl FigureMgr {
)
}
},
CharacterState::ChargedMelee(s) => {
let stage_time = s.timer.as_secs_f64();
let stage_progress = match s.stage_section {
StageSection::Charge => {
stage_time / s.static_data.charge_duration.as_secs_f64()
},
StageSection::Swing => {
stage_time / s.static_data.swing_duration.as_secs_f64()
},
StageSection::Recover => {
stage_time / s.static_data.recover_duration.as_secs_f64()
},
_ => 0.0,
};
anim::character::ChargeswingAnimation::update_skeleton(
&target_base,
(
active_tool_kind,
second_tool_kind,
vel.0,
time,
Some(s.stage_section),
),
stage_progress,
&mut state_animation_rate,
skeleton_attr,
)
},
CharacterState::ChargedRanged(data) => {
if data.exhausted {
anim::character::ShootAnimation::update_skeleton(
@ -874,6 +904,39 @@ impl FigureMgr {
)
}
},
CharacterState::RepeaterRanged(s) => {
let stage_time = s.timer.as_secs_f64();
let stage_progress = match s.stage_section {
StageSection::Buildup => {
stage_time / s.static_data.buildup_duration.as_secs_f64()
},
StageSection::Movement => {
stage_time / s.static_data.movement_duration.as_secs_f64()
},
StageSection::Shoot => {
stage_time / s.static_data.shoot_duration.as_secs_f64()
},
StageSection::Recover => {
stage_time / s.static_data.recover_duration.as_secs_f64()
},
_ => 0.0,
};
anim::character::RepeaterAnimation::update_skeleton(
&target_base,
(
active_tool_kind,
second_tool_kind,
vel.0,
time,
Some(s.stage_section),
),
stage_progress,
&mut state_animation_rate,
skeleton_attr,
)
},
CharacterState::Sneak { .. } => {
anim::character::SneakAnimation::update_skeleton(
&CharacterSkeleton::default(),
@ -928,11 +991,42 @@ impl FigureMgr {
skeleton_attr,
)
},
CharacterState::LeapMelee(_) => {
CharacterState::LeapMelee(s) => {
let stage_progress = match active_tool_kind {
Some(ToolKind::Axe(_) | ToolKind::Hammer(_)) => {
let stage_time = s.timer.as_secs_f64();
match s.stage_section {
StageSection::Buildup => {
stage_time
/ s.static_data.buildup_duration.as_secs_f64()
},
StageSection::Movement => {
stage_time
/ s.static_data.movement_duration.as_secs_f64()
},
StageSection::Swing => {
stage_time / s.static_data.swing_duration.as_secs_f64()
},
StageSection::Recover => {
stage_time
/ s.static_data.recover_duration.as_secs_f64()
},
_ => 0.0,
}
},
_ => state.state_time,
};
anim::character::LeapAnimation::update_skeleton(
&target_base,
(active_tool_kind, second_tool_kind, vel.0, time),
state.state_time,
(
active_tool_kind,
second_tool_kind,
vel.0,
time,
Some(s.stage_section),
),
stage_progress,
&mut state_animation_rate,
skeleton_attr,
)