mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sam/sword-overhaul' into 'master'
Sword overhaul Closes #763 and #761 See merge request veloren/veloren!1365
This commit is contained in:
commit
18b912ea6f
@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Figure meshing no longer blocks the main thread.
|
||||
- Overhauled persistence layer including no longer storing serialized JSON items in the database
|
||||
- Overhauled representation of blocks to permit fluid and sprite coexistence
|
||||
- Overhauled sword
|
||||
|
||||
### Removed
|
||||
|
||||
|
@ -6,7 +6,7 @@ ItemDef(
|
||||
kind: Sword("Zweihander0"),
|
||||
stats: (
|
||||
equip_time_millis: 500,
|
||||
power: 0.2,
|
||||
power: 0.75,
|
||||
),
|
||||
)
|
||||
),
|
||||
|
@ -94,19 +94,19 @@
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Attack(TripleStrike(First), Sword): (
|
||||
Attack(ComboMelee(Swing, 1), Sword): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.abilities.swing_sword",
|
||||
],
|
||||
threshold: 0.7,
|
||||
),
|
||||
Attack(TripleStrike(Second), Sword): (
|
||||
Attack(ComboMelee(Swing, 2), Sword): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.abilities.separated_second_swing",
|
||||
],
|
||||
threshold: 0.7,
|
||||
),
|
||||
Attack(TripleStrike(Third), Sword): (
|
||||
Attack(ComboMelee(Swing, 3), Sword): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.abilities.separated_third_swing",
|
||||
],
|
||||
@ -174,19 +174,7 @@
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Attack(TripleStrike(First), Axe): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.abilities.swing",
|
||||
],
|
||||
threshold: 0.7,
|
||||
),
|
||||
Attack(TripleStrike(Second), Axe): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.abilities.swing",
|
||||
],
|
||||
threshold: 0.7,
|
||||
),
|
||||
Attack(TripleStrike(Third), Axe): (
|
||||
Attack(BasicMelee, Axe): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.abilities.swing",
|
||||
],
|
||||
|
BIN
assets/voxygen/element/icons/sword_whirlwind.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/sword_whirlwind.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -1,10 +1,9 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
ability::Stage,
|
||||
item::{armor::Protection, Item, ItemKind},
|
||||
Body, CharacterState, EnergySource, Gravity, LightEmitter, Projectile, StateUpdate,
|
||||
},
|
||||
states::{triple_strike::*, *},
|
||||
states::{utils::StageSection, *},
|
||||
sys::character_behavior::JoinData,
|
||||
};
|
||||
use arraygen::Arraygen;
|
||||
@ -21,7 +20,7 @@ pub enum CharacterAbilityType {
|
||||
ChargedRanged,
|
||||
DashMelee,
|
||||
BasicBlock,
|
||||
TripleStrike(Stage),
|
||||
ComboMelee(StageSection, u32),
|
||||
LeapMelee,
|
||||
SpinMelee,
|
||||
GroundShockwave,
|
||||
@ -36,7 +35,7 @@ impl From<&CharacterState> for CharacterAbilityType {
|
||||
CharacterState::DashMelee(_) => Self::DashMelee,
|
||||
CharacterState::BasicBlock => Self::BasicBlock,
|
||||
CharacterState::LeapMelee(_) => Self::LeapMelee,
|
||||
CharacterState::TripleStrike(data) => Self::TripleStrike(data.stage),
|
||||
CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage_section, data.stage),
|
||||
CharacterState::SpinMelee(_) => Self::SpinMelee,
|
||||
CharacterState::ChargedRanged(_) => Self::ChargedRanged,
|
||||
CharacterState::GroundShockwave(_) => Self::ChargedRanged,
|
||||
@ -73,15 +72,31 @@ pub enum CharacterAbility {
|
||||
},
|
||||
DashMelee {
|
||||
energy_cost: u32,
|
||||
buildup_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
base_damage: u32,
|
||||
max_damage: u32,
|
||||
base_knockback: f32,
|
||||
max_knockback: f32,
|
||||
range: f32,
|
||||
angle: f32,
|
||||
energy_drain: u32,
|
||||
forward_speed: f32,
|
||||
buildup_duration: Duration,
|
||||
charge_duration: Duration,
|
||||
swing_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
infinite_charge: bool,
|
||||
is_interruptible: bool,
|
||||
},
|
||||
BasicBlock,
|
||||
Roll,
|
||||
TripleStrike {
|
||||
base_damage: u32,
|
||||
needs_timing: bool,
|
||||
ComboMelee {
|
||||
stage_data: Vec<combo_melee::Stage>,
|
||||
initial_energy_gain: u32,
|
||||
max_energy_gain: u32,
|
||||
energy_increase: u32,
|
||||
speed_increase: f32,
|
||||
max_speed_increase: f32,
|
||||
is_interruptible: bool,
|
||||
},
|
||||
LeapMelee {
|
||||
energy_cost: u32,
|
||||
@ -91,10 +106,18 @@ pub enum CharacterAbility {
|
||||
base_damage: u32,
|
||||
},
|
||||
SpinMelee {
|
||||
energy_cost: u32,
|
||||
buildup_duration: Duration,
|
||||
swing_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
base_damage: u32,
|
||||
knockback: f32,
|
||||
range: f32,
|
||||
energy_cost: u32,
|
||||
is_infinite: bool,
|
||||
is_helicopter: bool,
|
||||
is_interruptible: bool,
|
||||
forward_speed: f32,
|
||||
num_spins: u32,
|
||||
},
|
||||
ChargedRanged {
|
||||
energy_cost: u32,
|
||||
@ -130,11 +153,6 @@ impl CharacterAbility {
|
||||
/// applicable.
|
||||
pub fn requirements_paid(&self, data: &JoinData, update: &mut StateUpdate) -> bool {
|
||||
match self {
|
||||
CharacterAbility::TripleStrike { .. } => {
|
||||
data.physics.on_ground
|
||||
&& data.body.is_humanoid()
|
||||
&& data.inputs.look_dir.xy().magnitude_squared() > 0.01
|
||||
},
|
||||
CharacterAbility::Roll => {
|
||||
data.physics.on_ground
|
||||
&& data.body.is_humanoid()
|
||||
@ -313,35 +331,71 @@ impl From<&CharacterAbility> for CharacterState {
|
||||
}),
|
||||
CharacterAbility::DashMelee {
|
||||
energy_cost: _,
|
||||
buildup_duration,
|
||||
recover_duration,
|
||||
base_damage,
|
||||
max_damage,
|
||||
base_knockback,
|
||||
max_knockback,
|
||||
range,
|
||||
angle,
|
||||
energy_drain,
|
||||
forward_speed,
|
||||
buildup_duration,
|
||||
charge_duration,
|
||||
swing_duration,
|
||||
recover_duration,
|
||||
infinite_charge,
|
||||
is_interruptible,
|
||||
} => CharacterState::DashMelee(dash_melee::Data {
|
||||
initialize: true,
|
||||
static_data: dash_melee::StaticData {
|
||||
base_damage: *base_damage,
|
||||
max_damage: *max_damage,
|
||||
base_knockback: *base_knockback,
|
||||
max_knockback: *max_knockback,
|
||||
range: *range,
|
||||
angle: *angle,
|
||||
energy_drain: *energy_drain,
|
||||
forward_speed: *forward_speed,
|
||||
infinite_charge: *infinite_charge,
|
||||
buildup_duration: *buildup_duration,
|
||||
charge_duration: *charge_duration,
|
||||
swing_duration: *swing_duration,
|
||||
recover_duration: *recover_duration,
|
||||
is_interruptible: *is_interruptible,
|
||||
},
|
||||
end_charge: false,
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
exhausted: false,
|
||||
buildup_duration: *buildup_duration,
|
||||
recover_duration: *recover_duration,
|
||||
base_damage: *base_damage,
|
||||
}),
|
||||
CharacterAbility::BasicBlock => CharacterState::BasicBlock,
|
||||
CharacterAbility::Roll => CharacterState::Roll(roll::Data {
|
||||
remaining_duration: Duration::from_millis(500),
|
||||
was_wielded: false, // false by default. utils might set it to true
|
||||
}),
|
||||
CharacterAbility::TripleStrike {
|
||||
base_damage,
|
||||
needs_timing,
|
||||
} => CharacterState::TripleStrike(triple_strike::Data {
|
||||
base_damage: *base_damage,
|
||||
stage: triple_strike::Stage::First,
|
||||
stage_exhausted: false,
|
||||
stage_time_active: Duration::default(),
|
||||
initialized: false,
|
||||
transition_style: if *needs_timing {
|
||||
TransitionStyle::Timed(TimingState::NotPressed)
|
||||
} else {
|
||||
TransitionStyle::Hold(HoldingState::Holding)
|
||||
CharacterAbility::ComboMelee {
|
||||
stage_data,
|
||||
initial_energy_gain,
|
||||
max_energy_gain,
|
||||
energy_increase,
|
||||
speed_increase,
|
||||
max_speed_increase,
|
||||
is_interruptible,
|
||||
} => CharacterState::ComboMelee(combo_melee::Data {
|
||||
static_data: combo_melee::StaticData {
|
||||
num_stages: stage_data.len() as u32,
|
||||
stage_data: stage_data.clone(),
|
||||
initial_energy_gain: *initial_energy_gain,
|
||||
max_energy_gain: *max_energy_gain,
|
||||
energy_increase: *energy_increase,
|
||||
speed_increase: 1.0 - *speed_increase,
|
||||
max_speed_increase: *max_speed_increase - 1.0,
|
||||
is_interruptible: *is_interruptible,
|
||||
},
|
||||
stage: 1,
|
||||
combo: 0,
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
next_stage: false,
|
||||
}),
|
||||
CharacterAbility::LeapMelee {
|
||||
energy_cost: _,
|
||||
@ -358,24 +412,37 @@ impl From<&CharacterAbility> for CharacterState {
|
||||
base_damage: *base_damage,
|
||||
}),
|
||||
CharacterAbility::SpinMelee {
|
||||
energy_cost,
|
||||
buildup_duration,
|
||||
swing_duration,
|
||||
recover_duration,
|
||||
base_damage,
|
||||
knockback,
|
||||
range,
|
||||
energy_cost,
|
||||
is_infinite,
|
||||
is_helicopter,
|
||||
is_interruptible,
|
||||
forward_speed,
|
||||
num_spins,
|
||||
} => CharacterState::SpinMelee(spin_melee::Data {
|
||||
static_data: spin_melee::StaticData {
|
||||
buildup_duration: *buildup_duration,
|
||||
swing_duration: *swing_duration,
|
||||
recover_duration: *recover_duration,
|
||||
base_damage: *base_damage,
|
||||
knockback: *knockback,
|
||||
range: *range,
|
||||
energy_cost: *energy_cost,
|
||||
is_infinite: *is_infinite,
|
||||
is_helicopter: *is_helicopter,
|
||||
is_interruptible: *is_interruptible,
|
||||
forward_speed: *forward_speed,
|
||||
num_spins: *num_spins,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
spins_remaining: *num_spins - 1,
|
||||
stage_section: StageSection::Buildup,
|
||||
exhausted: false,
|
||||
energy_cost: *energy_cost,
|
||||
buildup_duration: *buildup_duration,
|
||||
buildup_duration_default: *buildup_duration,
|
||||
recover_duration: *recover_duration,
|
||||
recover_duration_default: *recover_duration,
|
||||
base_damage: *base_damage,
|
||||
// This isn't needed for it's continuous implementation, but is left in should this
|
||||
// skill be moved to the skillbar
|
||||
hits_remaining: 1,
|
||||
hits_remaining_default: 1, /* Should be the same value as hits_remaining, also
|
||||
* this value can be removed if ability moved to
|
||||
* skillbar */
|
||||
}),
|
||||
CharacterAbility::ChargedRanged {
|
||||
energy_cost: _,
|
||||
|
@ -62,7 +62,7 @@ pub enum CharacterState {
|
||||
DashMelee(dash_melee::Data),
|
||||
/// A three-stage attack where each attack pushes player forward
|
||||
/// and successive attacks increase in damage, while player holds button.
|
||||
TripleStrike(triple_strike::Data),
|
||||
ComboMelee(combo_melee::Data),
|
||||
/// A leap followed by a small aoe ground attack
|
||||
LeapMelee(leap_melee::Data),
|
||||
/// Spin around, dealing damage to enemies surrounding you
|
||||
@ -80,7 +80,7 @@ impl CharacterState {
|
||||
| CharacterState::BasicMelee(_)
|
||||
| CharacterState::BasicRanged(_)
|
||||
| CharacterState::DashMelee(_)
|
||||
| CharacterState::TripleStrike(_)
|
||||
| CharacterState::ComboMelee(_)
|
||||
| CharacterState::BasicBlock
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::SpinMelee(_)
|
||||
@ -94,7 +94,7 @@ impl CharacterState {
|
||||
CharacterState::BasicMelee(_)
|
||||
| CharacterState::BasicRanged(_)
|
||||
| CharacterState::DashMelee(_)
|
||||
| CharacterState::TripleStrike(_)
|
||||
| CharacterState::ComboMelee(_)
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::SpinMelee(_)
|
||||
| CharacterState::ChargedRanged(_)
|
||||
@ -107,7 +107,7 @@ impl CharacterState {
|
||||
CharacterState::BasicMelee(_)
|
||||
| CharacterState::BasicRanged(_)
|
||||
| CharacterState::DashMelee(_)
|
||||
| CharacterState::TripleStrike(_)
|
||||
| CharacterState::ComboMelee(_)
|
||||
| CharacterState::BasicBlock
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::ChargedRanged(_)
|
||||
|
@ -1,8 +1,9 @@
|
||||
// Note: If you changes here "break" old character saves you can change the
|
||||
// version in voxygen\src\meta.rs in order to reset save files to being empty
|
||||
|
||||
use crate::comp::{
|
||||
body::object, projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile,
|
||||
use crate::{
|
||||
comp::{body::object, projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile},
|
||||
states::combo_melee,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -116,27 +117,110 @@ impl Tool {
|
||||
|
||||
match &self.kind {
|
||||
Sword(_) => vec![
|
||||
TripleStrike {
|
||||
base_damage: (60.0 * self.base_power()) as u32,
|
||||
needs_timing: false,
|
||||
ComboMelee {
|
||||
stage_data: vec![
|
||||
combo_melee::Stage {
|
||||
stage: 1,
|
||||
base_damage: (100.0 * self.base_power()) as u32,
|
||||
max_damage: (120.0 * self.base_power()) as u32,
|
||||
damage_increase: (10.0 * self.base_power()) as u32,
|
||||
knockback: 10.0,
|
||||
range: 4.0,
|
||||
angle: 30.0,
|
||||
base_buildup_duration: Duration::from_millis(350),
|
||||
base_swing_duration: Duration::from_millis(100),
|
||||
base_recover_duration: Duration::from_millis(400),
|
||||
forward_movement: 0.5,
|
||||
},
|
||||
combo_melee::Stage {
|
||||
stage: 2,
|
||||
base_damage: (80.0 * self.base_power()) as u32,
|
||||
max_damage: (110.0 * self.base_power()) as u32,
|
||||
damage_increase: (15.0 * self.base_power()) as u32,
|
||||
knockback: 12.0,
|
||||
range: 3.5,
|
||||
angle: 180.0,
|
||||
base_buildup_duration: Duration::from_millis(400),
|
||||
base_swing_duration: Duration::from_millis(600),
|
||||
base_recover_duration: Duration::from_millis(400),
|
||||
forward_movement: 0.0,
|
||||
},
|
||||
combo_melee::Stage {
|
||||
stage: 3,
|
||||
base_damage: (130.0 * self.base_power()) as u32,
|
||||
max_damage: (170.0 * self.base_power()) as u32,
|
||||
damage_increase: (20.0 * self.base_power()) as u32,
|
||||
knockback: 14.0,
|
||||
range: 6.0,
|
||||
angle: 10.0,
|
||||
base_buildup_duration: Duration::from_millis(500),
|
||||
base_swing_duration: Duration::from_millis(200),
|
||||
base_recover_duration: Duration::from_millis(300),
|
||||
forward_movement: 1.2,
|
||||
},
|
||||
],
|
||||
initial_energy_gain: 0,
|
||||
max_energy_gain: 100,
|
||||
energy_increase: 20,
|
||||
speed_increase: 0.05,
|
||||
max_speed_increase: 1.8,
|
||||
is_interruptible: true,
|
||||
},
|
||||
DashMelee {
|
||||
energy_cost: 700,
|
||||
buildup_duration: Duration::from_millis(500),
|
||||
recover_duration: Duration::from_millis(500),
|
||||
energy_cost: 200,
|
||||
base_damage: (120.0 * self.base_power()) as u32,
|
||||
max_damage: (260.0 * self.base_power()) as u32,
|
||||
base_knockback: 10.0,
|
||||
max_knockback: 20.0,
|
||||
range: 5.0,
|
||||
angle: 45.0,
|
||||
energy_drain: 500,
|
||||
forward_speed: 4.0,
|
||||
buildup_duration: Duration::from_millis(250),
|
||||
charge_duration: Duration::from_millis(400),
|
||||
swing_duration: Duration::from_millis(100),
|
||||
recover_duration: Duration::from_millis(500),
|
||||
infinite_charge: true,
|
||||
is_interruptible: true,
|
||||
},
|
||||
SpinMelee {
|
||||
buildup_duration: Duration::from_millis(750),
|
||||
swing_duration: Duration::from_millis(500),
|
||||
recover_duration: Duration::from_millis(500),
|
||||
base_damage: (140.0 * self.base_power()) as u32,
|
||||
knockback: 10.0,
|
||||
range: 3.5,
|
||||
energy_cost: 200,
|
||||
is_infinite: false,
|
||||
is_helicopter: false,
|
||||
is_interruptible: true,
|
||||
forward_speed: 1.0,
|
||||
num_spins: 3,
|
||||
},
|
||||
],
|
||||
Axe(_) => vec![
|
||||
TripleStrike {
|
||||
base_damage: (80.0 * self.base_power()) as u32,
|
||||
needs_timing: true,
|
||||
BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: Duration::from_millis(700),
|
||||
recover_duration: Duration::from_millis(300),
|
||||
base_healthchange: (-120.0 * self.base_power()) as i32,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 20.0,
|
||||
},
|
||||
SpinMelee {
|
||||
energy_cost: 100,
|
||||
buildup_duration: Duration::from_millis(125),
|
||||
recover_duration: Duration::from_millis(125),
|
||||
buildup_duration: Duration::from_millis(100),
|
||||
swing_duration: Duration::from_millis(250),
|
||||
recover_duration: Duration::from_millis(100),
|
||||
base_damage: (60.0 * self.base_power()) as u32,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
energy_cost: 100,
|
||||
is_infinite: true,
|
||||
is_helicopter: true,
|
||||
is_interruptible: false,
|
||||
forward_speed: 0.0,
|
||||
num_spins: 1,
|
||||
},
|
||||
],
|
||||
Hammer(_) => vec![
|
||||
@ -206,23 +290,15 @@ impl Tool {
|
||||
max_projectile_speed: 500.0,
|
||||
},
|
||||
],
|
||||
Dagger(_) => vec![
|
||||
BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: Duration::from_millis(100),
|
||||
recover_duration: Duration::from_millis(400),
|
||||
base_healthchange: (-50.0 * self.base_power()) as i32,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 20.0,
|
||||
},
|
||||
DashMelee {
|
||||
energy_cost: 700,
|
||||
buildup_duration: Duration::from_millis(500),
|
||||
recover_duration: Duration::from_millis(500),
|
||||
base_damage: (100.0 * self.base_power()) as u32,
|
||||
},
|
||||
],
|
||||
Dagger(_) => vec![BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: Duration::from_millis(100),
|
||||
recover_duration: Duration::from_millis(400),
|
||||
base_healthchange: (-50.0 * self.base_power()) as i32,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 20.0,
|
||||
}],
|
||||
Staff(kind) => {
|
||||
if kind == "Sceptre" {
|
||||
vec![
|
||||
|
@ -66,7 +66,12 @@ impl LoadoutBuilder {
|
||||
}
|
||||
|
||||
/// Builds loadout of creature when spawned
|
||||
pub fn build_loadout(body: Body, alignment: Alignment, mut main_tool: Option<Item>) -> Self {
|
||||
pub fn build_loadout(
|
||||
body: Body,
|
||||
alignment: Alignment,
|
||||
mut main_tool: Option<Item>,
|
||||
is_giant: bool,
|
||||
) -> Self {
|
||||
#![allow(clippy::single_match)] // For when this is done to more than just golems.
|
||||
match body {
|
||||
Body::Golem(golem) => match golem.species {
|
||||
@ -76,6 +81,13 @@ impl LoadoutBuilder {
|
||||
));
|
||||
},
|
||||
},
|
||||
Body::Humanoid(_) => {
|
||||
if is_giant {
|
||||
main_tool = Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.sword.zweihander_sword_0",
|
||||
));
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
|
||||
@ -112,78 +124,114 @@ impl LoadoutBuilder {
|
||||
};
|
||||
|
||||
let loadout = match body {
|
||||
Body::Humanoid(_) => match alignment {
|
||||
Alignment::Npc => Loadout {
|
||||
active_item,
|
||||
second_item: None,
|
||||
shoulder: None,
|
||||
chest: Some(Item::new_from_asset_expect(
|
||||
match rand::thread_rng().gen_range(0, 10) {
|
||||
0 => "common.items.armor.chest.worker_green_0",
|
||||
1 => "common.items.armor.chest.worker_green_1",
|
||||
2 => "common.items.armor.chest.worker_red_0",
|
||||
3 => "common.items.armor.chest.worker_red_1",
|
||||
4 => "common.items.armor.chest.worker_purple_0",
|
||||
5 => "common.items.armor.chest.worker_purple_1",
|
||||
6 => "common.items.armor.chest.worker_yellow_0",
|
||||
7 => "common.items.armor.chest.worker_yellow_1",
|
||||
8 => "common.items.armor.chest.worker_orange_0",
|
||||
_ => "common.items.armor.chest.worker_orange_1",
|
||||
Body::Humanoid(_) => {
|
||||
if is_giant {
|
||||
Loadout {
|
||||
active_item,
|
||||
second_item: None,
|
||||
shoulder: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.shoulder.plate_0",
|
||||
)),
|
||||
chest: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.chest.plate_green_0",
|
||||
)),
|
||||
belt: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.belt.plate_0",
|
||||
)),
|
||||
hand: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.hand.plate_0",
|
||||
)),
|
||||
pants: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.pants.plate_green_0",
|
||||
)),
|
||||
foot: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.foot.plate_0",
|
||||
)),
|
||||
back: None,
|
||||
ring: None,
|
||||
neck: None,
|
||||
lantern: None,
|
||||
glider: None,
|
||||
head: None,
|
||||
tabard: None,
|
||||
}
|
||||
} else {
|
||||
match alignment {
|
||||
Alignment::Npc => Loadout {
|
||||
active_item,
|
||||
second_item: None,
|
||||
shoulder: None,
|
||||
chest: Some(Item::new_from_asset_expect(
|
||||
match rand::thread_rng().gen_range(0, 10) {
|
||||
0 => "common.items.armor.chest.worker_green_0",
|
||||
1 => "common.items.armor.chest.worker_green_1",
|
||||
2 => "common.items.armor.chest.worker_red_0",
|
||||
3 => "common.items.armor.chest.worker_red_1",
|
||||
4 => "common.items.armor.chest.worker_purple_0",
|
||||
5 => "common.items.armor.chest.worker_purple_1",
|
||||
6 => "common.items.armor.chest.worker_yellow_0",
|
||||
7 => "common.items.armor.chest.worker_yellow_1",
|
||||
8 => "common.items.armor.chest.worker_orange_0",
|
||||
_ => "common.items.armor.chest.worker_orange_1",
|
||||
},
|
||||
)),
|
||||
belt: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.belt.leather_0",
|
||||
)),
|
||||
hand: None,
|
||||
pants: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.pants.worker_blue_0",
|
||||
)),
|
||||
foot: Some(Item::new_from_asset_expect(
|
||||
match rand::thread_rng().gen_range(0, 2) {
|
||||
0 => "common.items.armor.foot.leather_0",
|
||||
_ => "common.items.armor.starter.sandals_0",
|
||||
},
|
||||
)),
|
||||
back: None,
|
||||
ring: None,
|
||||
neck: None,
|
||||
lantern: None,
|
||||
glider: None,
|
||||
head: None,
|
||||
tabard: None,
|
||||
},
|
||||
)),
|
||||
belt: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.belt.leather_0",
|
||||
)),
|
||||
hand: None,
|
||||
pants: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.pants.worker_blue_0",
|
||||
)),
|
||||
foot: Some(Item::new_from_asset_expect(
|
||||
match rand::thread_rng().gen_range(0, 2) {
|
||||
0 => "common.items.armor.foot.leather_0",
|
||||
_ => "common.items.armor.starter.sandals_0",
|
||||
Alignment::Enemy => Loadout {
|
||||
active_item,
|
||||
second_item: None,
|
||||
shoulder: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.shoulder.cultist_shoulder_purple",
|
||||
)),
|
||||
chest: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.chest.cultist_chest_purple",
|
||||
)),
|
||||
belt: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.belt.cultist_belt",
|
||||
)),
|
||||
hand: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.hand.cultist_hands_purple",
|
||||
)),
|
||||
pants: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.pants.cultist_legs_purple",
|
||||
)),
|
||||
foot: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.foot.cultist_boots",
|
||||
)),
|
||||
back: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.back.dungeon_purple-0",
|
||||
)),
|
||||
ring: None,
|
||||
neck: None,
|
||||
lantern: Some(Item::new_from_asset_expect(
|
||||
"common.items.lantern.black_0",
|
||||
)),
|
||||
glider: None,
|
||||
head: None,
|
||||
tabard: None,
|
||||
},
|
||||
)),
|
||||
back: None,
|
||||
ring: None,
|
||||
neck: None,
|
||||
lantern: None,
|
||||
glider: None,
|
||||
head: None,
|
||||
tabard: None,
|
||||
},
|
||||
Alignment::Enemy => Loadout {
|
||||
active_item,
|
||||
second_item: None,
|
||||
shoulder: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.shoulder.cultist_shoulder_purple",
|
||||
)),
|
||||
chest: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.chest.cultist_chest_purple",
|
||||
)),
|
||||
belt: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.belt.cultist_belt",
|
||||
)),
|
||||
hand: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.hand.cultist_hands_purple",
|
||||
)),
|
||||
pants: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.pants.cultist_legs_purple",
|
||||
)),
|
||||
foot: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.foot.cultist_boots",
|
||||
)),
|
||||
back: Some(Item::new_from_asset_expect(
|
||||
"common.items.armor.back.dungeon_purple-0",
|
||||
)),
|
||||
ring: None,
|
||||
neck: None,
|
||||
lantern: Some(Item::new_from_asset_expect("common.items.lantern.black_0")),
|
||||
glider: None,
|
||||
head: None,
|
||||
tabard: None,
|
||||
},
|
||||
_ => LoadoutBuilder::animal(body).build(),
|
||||
_ => LoadoutBuilder::animal(body).build(),
|
||||
}
|
||||
}
|
||||
},
|
||||
Body::Golem(golem) => match golem.species {
|
||||
golem::Species::StoneGolem => Loadout {
|
||||
|
275
common/src/states/combo_melee.rs
Normal file
275
common/src/states/combo_melee.rs
Normal file
@ -0,0 +1,275 @@
|
||||
use crate::{
|
||||
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
|
||||
states::utils::{StageSection, *},
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Stage {
|
||||
/// 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,
|
||||
/// 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: Duration,
|
||||
/// Duration of stage spent in swing (controls animation stuff, and can also
|
||||
/// be used to handle movement separately to buildup)
|
||||
pub base_swing_duration: Duration,
|
||||
/// Initial recover duration of stage (how long until character exits state)
|
||||
pub base_recover_duration: Duration,
|
||||
/// How much forward movement there is in the swing portion of the stage
|
||||
pub forward_movement: f32,
|
||||
}
|
||||
|
||||
#[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>,
|
||||
/// 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,
|
||||
}
|
||||
/// 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);
|
||||
|
||||
let stage_index = (self.stage - 1) as usize;
|
||||
|
||||
// Allows for other states to interrupt this state
|
||||
if self.static_data.is_interruptible && !data.inputs.primary.is_pressed() {
|
||||
handle_interrupt(data, &mut update);
|
||||
match update.character {
|
||||
CharacterState::ComboMelee(_) => {},
|
||||
_ => {
|
||||
return update;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
stage: self.stage,
|
||||
combo: self.combo,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(
|
||||
(1.0 + self.static_data.max_speed_increase
|
||||
* (1.0
|
||||
- self.static_data.speed_increase.powi(self.combo as i32)))
|
||||
* data.dt.0,
|
||||
))
|
||||
.unwrap_or_default(),
|
||||
stage_section: self.stage_section,
|
||||
next_stage: self.next_stage,
|
||||
});
|
||||
} else {
|
||||
// Transitions to swing section of stage
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
stage: self.stage,
|
||||
combo: self.combo,
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Swing,
|
||||
next_stage: self.next_stage,
|
||||
});
|
||||
|
||||
// Hit attempt
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
base_healthchange: -((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,
|
||||
)) as i32),
|
||||
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: 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
|
||||
forward_move(
|
||||
data,
|
||||
&mut update,
|
||||
0.3,
|
||||
self.static_data.stage_data[stage_index].forward_movement,
|
||||
);
|
||||
|
||||
// Swings
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
stage: self.stage,
|
||||
combo: self.combo,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(
|
||||
(1.0 + self.static_data.max_speed_increase
|
||||
* (1.0
|
||||
- self.static_data.speed_increase.powi(self.combo as i32)))
|
||||
* data.dt.0,
|
||||
))
|
||||
.unwrap_or_default(),
|
||||
stage_section: self.stage_section,
|
||||
next_stage: self.next_stage,
|
||||
});
|
||||
} else {
|
||||
// Transitions to recover section of stage
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
stage: self.stage,
|
||||
combo: self.combo,
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Recover,
|
||||
next_stage: self.next_stage,
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Recover => {
|
||||
if self.timer < self.static_data.stage_data[stage_index].base_recover_duration {
|
||||
// Recovers
|
||||
if data.inputs.primary.is_pressed() {
|
||||
// Checks if state will transition to next stage after recover
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
stage: self.stage,
|
||||
combo: self.combo,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(
|
||||
(1.0 + self.static_data.max_speed_increase
|
||||
* (1.0
|
||||
- self
|
||||
.static_data
|
||||
.speed_increase
|
||||
.powi(self.combo as i32)))
|
||||
* data.dt.0,
|
||||
))
|
||||
.unwrap_or_default(),
|
||||
stage_section: self.stage_section,
|
||||
next_stage: true,
|
||||
});
|
||||
} else {
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
stage: self.stage,
|
||||
combo: self.combo,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(
|
||||
(1.0 + self.static_data.max_speed_increase
|
||||
* (1.0
|
||||
- self
|
||||
.static_data
|
||||
.speed_increase
|
||||
.powi(self.combo as i32)))
|
||||
* data.dt.0,
|
||||
))
|
||||
.unwrap_or_default(),
|
||||
stage_section: self.stage_section,
|
||||
next_stage: self.next_stage,
|
||||
});
|
||||
}
|
||||
} 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,
|
||||
combo: self.combo,
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
next_stage: false,
|
||||
});
|
||||
} 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(energy, EnergySource::HitEnemy);
|
||||
}
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
}
|
@ -1,93 +1,256 @@
|
||||
use crate::{
|
||||
comp::{Attacking, CharacterState, StateUpdate},
|
||||
states::utils::*,
|
||||
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
|
||||
states::utils::{StageSection, *},
|
||||
sys::character_behavior::*,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
const DASH_SPEED: f32 = 19.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 much damage the attack initially does
|
||||
pub base_damage: u32,
|
||||
/// How much damage the attack does at max charge distance
|
||||
pub max_damage: u32,
|
||||
/// How much the attack knocks the target back initially
|
||||
pub base_knockback: f32,
|
||||
/// How much knockback happens at max charge distance
|
||||
pub max_knockback: f32,
|
||||
/// Range of the attack
|
||||
pub range: f32,
|
||||
/// Angle of the attack
|
||||
pub angle: f32,
|
||||
/// Rate of energy drain
|
||||
pub energy_drain: u32,
|
||||
/// How quickly dasher moves forward
|
||||
pub forward_speed: f32,
|
||||
/// Whether state keeps charging after reaching max charge duration
|
||||
pub infinite_charge: bool,
|
||||
/// How long until state should deal damage
|
||||
pub buildup_duration: Duration,
|
||||
/// How long the state charges for until it reaches max damage
|
||||
pub charge_duration: Duration,
|
||||
/// Suration of state spent in swing
|
||||
pub swing_duration: Duration,
|
||||
/// How long the state has until exiting
|
||||
pub recover_duration: Duration,
|
||||
/// Base damage
|
||||
pub base_damage: u32,
|
||||
/// Whether the attack can deal more damage
|
||||
/// Whether the state can be interrupted by other abilities
|
||||
pub is_interruptible: bool,
|
||||
}
|
||||
|
||||
#[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,
|
||||
/// Whether the charge should end
|
||||
pub end_charge: bool,
|
||||
/// Timer for each stage
|
||||
pub timer: Duration,
|
||||
/// What section the character stage is in
|
||||
pub stage_section: StageSection,
|
||||
/// Whether the state should attempt attacking again
|
||||
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_orientation(data, &mut update, 1.0);
|
||||
handle_move(data, &mut update, 0.1);
|
||||
|
||||
// Allows for other states to interrupt this state
|
||||
if self.static_data.is_interruptible && !data.inputs.secondary.is_pressed() {
|
||||
handle_interrupt(data, &mut update);
|
||||
match update.character {
|
||||
CharacterState::DashMelee(_) => {},
|
||||
_ => {
|
||||
return update;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if self.buildup_duration != Duration::default() && data.physics.touch_entities.is_empty() {
|
||||
// Build up (this will move you forward)
|
||||
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
|
||||
+ (update.vel.0 * Vec3::new(1.0, 1.0, 0.0)
|
||||
+ 1.5 * data.inputs.move_dir.try_normalized().unwrap_or_default())
|
||||
.try_normalized()
|
||||
.unwrap_or_default()
|
||||
* DASH_SPEED;
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
if self.timer < self.static_data.buildup_duration {
|
||||
// Build up
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: self.end_charge,
|
||||
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 charge section of stage
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: self.end_charge,
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Charge,
|
||||
exhausted: self.exhausted,
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Charge => {
|
||||
if (self.timer < self.static_data.charge_duration
|
||||
|| (self.static_data.infinite_charge && data.inputs.secondary.is_pressed()))
|
||||
&& update.energy.current() > 0
|
||||
&& !self.end_charge
|
||||
{
|
||||
// Forward movement
|
||||
forward_move(data, &mut update, 0.1, self.static_data.forward_speed);
|
||||
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
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_healthchange: -(self.base_damage as i32),
|
||||
range: 3.5,
|
||||
max_angle: 45_f32.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
knockback: 0.0,
|
||||
});
|
||||
// Hit attempt (also checks if player is moving)
|
||||
if !self.exhausted && update.vel.0.distance_squared(Vec3::zero()) > 1.0 {
|
||||
let charge_frac = (self.timer.as_secs_f32()
|
||||
/ self.static_data.charge_duration.as_secs_f32())
|
||||
.min(1.0);
|
||||
let damage = (self.static_data.max_damage as f32
|
||||
- self.static_data.base_damage as f32)
|
||||
* charge_frac
|
||||
+ self.static_data.base_damage as f32;
|
||||
let knockback = (self.static_data.max_knockback
|
||||
- self.static_data.base_knockback)
|
||||
* charge_frac
|
||||
+ self.static_data.base_knockback;
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
base_healthchange: -damage as i32,
|
||||
range: self.static_data.range,
|
||||
max_angle: self.static_data.angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
knockback,
|
||||
});
|
||||
}
|
||||
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
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::DashMelee(Data {
|
||||
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);
|
||||
// This logic basically just decides if a charge should end, and prevents the
|
||||
// character state spamming attacks while checking if it has hit something
|
||||
if !self.exhausted {
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: self.end_charge,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
stage_section: StageSection::Charge,
|
||||
exhausted: true,
|
||||
})
|
||||
} else if let Some(attack) = data.attacking {
|
||||
if attack.applied && attack.hit_count > 0 {
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: !self.static_data.infinite_charge,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
stage_section: StageSection::Charge,
|
||||
exhausted: false,
|
||||
})
|
||||
} else if attack.applied {
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: self.end_charge,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
stage_section: StageSection::Charge,
|
||||
exhausted: false,
|
||||
})
|
||||
} else {
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: !self.static_data.infinite_charge,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
stage_section: StageSection::Charge,
|
||||
exhausted: self.exhausted,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: !self.static_data.infinite_charge,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
stage_section: StageSection::Charge,
|
||||
exhausted: self.exhausted,
|
||||
})
|
||||
}
|
||||
|
||||
// Consumes energy if there's enough left and charge has not stopped
|
||||
update.energy.change_by(
|
||||
-(self.static_data.energy_drain as f32 * data.dt.0) as i32,
|
||||
EnergySource::Ability,
|
||||
);
|
||||
} else {
|
||||
// Transitions to swing section of stage
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: self.end_charge,
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Swing,
|
||||
exhausted: self.exhausted,
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Swing => {
|
||||
if self.timer < self.static_data.swing_duration {
|
||||
// Swings
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: self.end_charge,
|
||||
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 section of stage
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: self.end_charge,
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Recover,
|
||||
exhausted: self.exhausted,
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Recover => {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recover
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
static_data: self.static_data,
|
||||
end_charge: self.end_charge,
|
||||
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);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
update
|
||||
|
@ -4,6 +4,7 @@ pub mod basic_ranged;
|
||||
pub mod boost;
|
||||
pub mod charged_ranged;
|
||||
pub mod climb;
|
||||
pub mod combo_melee;
|
||||
pub mod dance;
|
||||
pub mod dash_melee;
|
||||
pub mod equipping;
|
||||
@ -16,6 +17,5 @@ pub mod roll;
|
||||
pub mod sit;
|
||||
pub mod sneak;
|
||||
pub mod spin_melee;
|
||||
pub mod triple_strike;
|
||||
pub mod utils;
|
||||
pub mod wielding;
|
||||
|
@ -1,136 +1,193 @@
|
||||
use crate::{
|
||||
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
|
||||
states::utils::{StageSection, *},
|
||||
sys::character_behavior::*,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
#[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 until the state attacks
|
||||
pub buildup_duration: Duration,
|
||||
/// Allows for buildup_duration to be reset to default value
|
||||
pub buildup_duration_default: Duration,
|
||||
/// How long the state is in the swing duration
|
||||
pub swing_duration: Duration,
|
||||
/// How long until state ends
|
||||
pub recover_duration: Duration,
|
||||
/// Allows for recover_duration to be reset to default value
|
||||
pub recover_duration_default: Duration,
|
||||
/// Base damage
|
||||
pub base_damage: u32,
|
||||
/// Whether the attack can deal more damage
|
||||
pub exhausted: bool,
|
||||
/// How many hits it can do before ending
|
||||
pub hits_remaining: u32,
|
||||
/// Allows for hits_remaining to be reset to default value
|
||||
pub hits_remaining_default: u32,
|
||||
/// Knockback
|
||||
pub knockback: f32,
|
||||
/// Range
|
||||
pub range: f32,
|
||||
/// Energy cost per attack
|
||||
pub energy_cost: u32,
|
||||
/// Whether spin state is infinite
|
||||
pub is_infinite: bool,
|
||||
/// Used to maintain classic axe spin physics
|
||||
pub is_helicopter: bool,
|
||||
/// Whether the state can be interrupted by other abilities
|
||||
pub is_interruptible: bool,
|
||||
/// Used for forced forward movement
|
||||
pub forward_speed: f32,
|
||||
/// Number of spins
|
||||
pub num_spins: u32,
|
||||
}
|
||||
|
||||
const MOVE_SPEED: f32 = 5.0;
|
||||
#[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,
|
||||
/// How many spins it can do before ending
|
||||
pub spins_remaining: u32,
|
||||
/// What section the character stage is in
|
||||
pub stage_section: StageSection,
|
||||
/// Whether the state can deal damage
|
||||
pub exhausted: bool,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
if self.buildup_duration != Duration::default() {
|
||||
// Allows for moving
|
||||
update.vel.0 =
|
||||
Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * MOVE_SPEED;
|
||||
if self.static_data.is_helicopter {
|
||||
update.vel.0 = Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * 5.0;
|
||||
}
|
||||
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
buildup_duration: self
|
||||
.buildup_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
buildup_duration_default: self.buildup_duration_default,
|
||||
recover_duration: self.recover_duration,
|
||||
recover_duration_default: self.recover_duration_default,
|
||||
base_damage: self.base_damage,
|
||||
exhausted: self.exhausted,
|
||||
hits_remaining: self.hits_remaining,
|
||||
hits_remaining_default: self.hits_remaining_default,
|
||||
energy_cost: self.energy_cost,
|
||||
});
|
||||
} else if !self.exhausted {
|
||||
//Hit attempt
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
base_healthchange: -(self.base_damage as i32),
|
||||
range: 3.5,
|
||||
max_angle: 360_f32.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
knockback: 0.0,
|
||||
});
|
||||
// Allows for other states to interrupt this state
|
||||
if self.static_data.is_interruptible && !data.inputs.ability3.is_pressed() {
|
||||
handle_interrupt(data, &mut update);
|
||||
match update.character {
|
||||
CharacterState::SpinMelee(_) => {},
|
||||
_ => {
|
||||
return update;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
buildup_duration: self.buildup_duration,
|
||||
buildup_duration_default: self.buildup_duration_default,
|
||||
recover_duration: self.recover_duration,
|
||||
recover_duration_default: self.recover_duration_default,
|
||||
base_damage: self.base_damage,
|
||||
exhausted: true,
|
||||
hits_remaining: self.hits_remaining - 1,
|
||||
hits_remaining_default: self.hits_remaining_default,
|
||||
energy_cost: self.energy_cost,
|
||||
});
|
||||
} else if self.recover_duration != Duration::default() {
|
||||
// Allows for moving
|
||||
update.vel.0 =
|
||||
Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * MOVE_SPEED;
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
if self.timer < self.static_data.buildup_duration {
|
||||
// Build up
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
static_data: self.static_data,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
spins_remaining: self.spins_remaining,
|
||||
stage_section: self.stage_section,
|
||||
exhausted: self.exhausted,
|
||||
});
|
||||
} else {
|
||||
// Transitions to swing section of stage
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
static_data: self.static_data,
|
||||
timer: Duration::default(),
|
||||
spins_remaining: self.spins_remaining,
|
||||
stage_section: StageSection::Swing,
|
||||
exhausted: self.exhausted,
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Swing => {
|
||||
if !self.exhausted {
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
static_data: self.static_data,
|
||||
timer: Duration::default(),
|
||||
spins_remaining: self.spins_remaining,
|
||||
stage_section: self.stage_section,
|
||||
exhausted: true,
|
||||
});
|
||||
// Hit attempt
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
base_healthchange: -(self.static_data.base_damage as i32),
|
||||
range: self.static_data.range,
|
||||
max_angle: 180_f32.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
knockback: self.static_data.knockback,
|
||||
});
|
||||
} else if self.timer < self.static_data.swing_duration {
|
||||
if !self.static_data.is_helicopter {
|
||||
forward_move(data, &mut update, 0.1, self.static_data.forward_speed);
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
}
|
||||
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
buildup_duration: self.buildup_duration,
|
||||
buildup_duration_default: self.buildup_duration_default,
|
||||
recover_duration: self
|
||||
.recover_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
recover_duration_default: self.recover_duration_default,
|
||||
base_damage: self.base_damage,
|
||||
exhausted: self.exhausted,
|
||||
hits_remaining: self.hits_remaining,
|
||||
hits_remaining_default: self.hits_remaining_default,
|
||||
energy_cost: self.energy_cost,
|
||||
});
|
||||
} else if self.hits_remaining != 0 {
|
||||
// Allows for one ability usage to have multiple hits
|
||||
// This isn't needed for it's continuous implementation, but is left in should
|
||||
// this skill be moved to the skillbar
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
buildup_duration: self.buildup_duration_default,
|
||||
buildup_duration_default: self.buildup_duration_default,
|
||||
recover_duration: self.recover_duration_default,
|
||||
recover_duration_default: self.recover_duration_default,
|
||||
base_damage: self.base_damage,
|
||||
exhausted: false,
|
||||
hits_remaining: self.hits_remaining,
|
||||
hits_remaining_default: self.hits_remaining_default,
|
||||
energy_cost: self.energy_cost,
|
||||
});
|
||||
} else if update.energy.current() >= self.energy_cost && data.inputs.secondary.is_pressed()
|
||||
{
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
buildup_duration: self.buildup_duration_default,
|
||||
buildup_duration_default: self.buildup_duration_default,
|
||||
recover_duration: self.recover_duration_default,
|
||||
recover_duration_default: self.recover_duration_default,
|
||||
base_damage: self.base_damage,
|
||||
exhausted: false,
|
||||
hits_remaining: self.hits_remaining_default,
|
||||
hits_remaining_default: self.hits_remaining_default,
|
||||
energy_cost: self.energy_cost,
|
||||
});
|
||||
// Consumes energy if there's enough left and RMB is held down
|
||||
update
|
||||
.energy
|
||||
.change_by(-(self.energy_cost as i32), EnergySource::Ability);
|
||||
} else {
|
||||
// Done
|
||||
update.character = CharacterState::Wielding;
|
||||
// Make sure attack component is removed
|
||||
data.updater.remove::<Attacking>(data.entity);
|
||||
// Swings
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
static_data: self.static_data,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
spins_remaining: self.spins_remaining,
|
||||
stage_section: self.stage_section,
|
||||
exhausted: self.exhausted,
|
||||
});
|
||||
} else if update.energy.current() >= self.static_data.energy_cost
|
||||
&& (self.spins_remaining != 0
|
||||
|| (self.static_data.is_infinite && data.inputs.secondary.is_pressed()))
|
||||
{
|
||||
let new_spins_remaining = if self.static_data.is_infinite {
|
||||
self.spins_remaining
|
||||
} else {
|
||||
self.spins_remaining - 1
|
||||
};
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
static_data: self.static_data,
|
||||
timer: Duration::default(),
|
||||
spins_remaining: new_spins_remaining,
|
||||
stage_section: self.stage_section,
|
||||
exhausted: false,
|
||||
});
|
||||
// Consumes energy if there's enough left and RMB is held down
|
||||
update.energy.change_by(
|
||||
-(self.static_data.energy_cost as i32),
|
||||
EnergySource::Ability,
|
||||
);
|
||||
} else {
|
||||
// Transitions to recover section of stage
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
static_data: self.static_data,
|
||||
timer: Duration::default(),
|
||||
spins_remaining: self.spins_remaining,
|
||||
stage_section: StageSection::Recover,
|
||||
exhausted: self.exhausted,
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Recover => {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recover
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
static_data: self.static_data,
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
spins_remaining: self.spins_remaining,
|
||||
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
|
||||
|
@ -1,220 +0,0 @@
|
||||
use crate::{
|
||||
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
|
||||
states::utils::*,
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use vek::vec::Vec3;
|
||||
use HoldingState::*;
|
||||
use TimingState::*;
|
||||
use TransitionStyle::*;
|
||||
|
||||
// In millis
|
||||
const STAGE_DURATION: u64 = 700;
|
||||
const TIMING_DELAY: u64 = 350;
|
||||
const INITIAL_ACCEL: f32 = 90.0;
|
||||
const BASE_SPEED: f32 = 25.0;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum Stage {
|
||||
First,
|
||||
Second,
|
||||
Third,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum TimingState {
|
||||
NotPressed,
|
||||
PressedEarly,
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum HoldingState {
|
||||
Holding,
|
||||
Released,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum TransitionStyle {
|
||||
/// Player must time a button press properly to transition
|
||||
Timed(TimingState),
|
||||
/// Player must hold button for whole move
|
||||
Hold(HoldingState),
|
||||
}
|
||||
|
||||
/// ### A sequence of 3 incrementally increasing attacks.
|
||||
///
|
||||
/// While holding down the `primary` button, perform a series of 3 attacks,
|
||||
/// each one pushes the player forward as the character steps into the swings.
|
||||
/// The player can let go of the left mouse button at any time
|
||||
/// and stop their attacks by interrupting the attack animation.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct Data {
|
||||
/// The tool this state will read to handle damage, etc.
|
||||
pub base_damage: u32,
|
||||
/// What stage (of 3) the attack is in
|
||||
pub stage: Stage,
|
||||
/// How long current stage has been active
|
||||
pub stage_time_active: Duration,
|
||||
/// Whether current stage has exhausted its attack
|
||||
pub stage_exhausted: bool,
|
||||
/// Whether state has performed initialization logic
|
||||
pub initialized: bool,
|
||||
/// What this instance's current transition stat is
|
||||
pub transition_style: TransitionStyle,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_move(data, &mut update, 0.3);
|
||||
|
||||
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
||||
let stage_time_active = self
|
||||
.stage_time_active
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or(Duration::default());
|
||||
|
||||
if !self.initialized {
|
||||
update.vel.0 = Vec3::zero();
|
||||
if let Some(dir) = data.inputs.look_dir.try_normalized() {
|
||||
update.ori.0 = dir.into();
|
||||
}
|
||||
}
|
||||
let initialized = true;
|
||||
|
||||
// Update transition
|
||||
let transition_style = match self.transition_style {
|
||||
Timed(state) => match state {
|
||||
NotPressed => {
|
||||
if data.inputs.primary.is_just_pressed() {
|
||||
if stage_time_active > Duration::from_millis(TIMING_DELAY) {
|
||||
Timed(Success)
|
||||
} else {
|
||||
Timed(PressedEarly)
|
||||
}
|
||||
} else {
|
||||
self.transition_style
|
||||
}
|
||||
},
|
||||
_ => self.transition_style,
|
||||
},
|
||||
Hold(_) => {
|
||||
if !data.inputs.primary.is_pressed() {
|
||||
Hold(Released)
|
||||
} else {
|
||||
self.transition_style
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Handling movement
|
||||
if stage_time_active < Duration::from_millis(STAGE_DURATION / 3) {
|
||||
let adjusted_accel = match (self.stage, data.physics.touch_entities.is_empty()) {
|
||||
(Stage::First, true) => INITIAL_ACCEL,
|
||||
(Stage::Second, true) => INITIAL_ACCEL * 0.75,
|
||||
(Stage::Third, true) => INITIAL_ACCEL * 0.75,
|
||||
(_, _) => 0.0,
|
||||
};
|
||||
|
||||
// Move player forward while in first third of each stage
|
||||
if update.vel.0.magnitude_squared() < BASE_SPEED.powf(2.0) {
|
||||
update.vel.0 += data.dt.0 * (adjusted_accel * Vec3::from(data.ori.0.xy()));
|
||||
let mag2 = update.vel.0.magnitude_squared();
|
||||
if mag2 > BASE_SPEED.powf(2.0) {
|
||||
update.vel.0 = update.vel.0.normalized() * BASE_SPEED;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
handle_orientation(data, &mut update, 50.0);
|
||||
}
|
||||
|
||||
// Handling attacking
|
||||
update.character = if stage_time_active > Duration::from_millis(STAGE_DURATION / 2)
|
||||
&& !self.stage_exhausted
|
||||
{
|
||||
let dmg = match self.stage {
|
||||
Stage::First => self.base_damage / 2,
|
||||
Stage::Second => self.base_damage,
|
||||
Stage::Third => (self.base_damage as f32 * 1.5) as u32,
|
||||
};
|
||||
|
||||
update.vel.0 = Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * 5.0;
|
||||
|
||||
// Try to deal damage in second half of stage
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
base_healthchange: -(dmg as i32),
|
||||
range: 3.5,
|
||||
max_angle: 45_f32.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
knockback: 10.0,
|
||||
});
|
||||
|
||||
CharacterState::TripleStrike(Data {
|
||||
base_damage: self.base_damage,
|
||||
stage: self.stage,
|
||||
stage_time_active,
|
||||
stage_exhausted: true,
|
||||
initialized,
|
||||
transition_style,
|
||||
})
|
||||
} else if stage_time_active > Duration::from_millis(STAGE_DURATION) {
|
||||
let next_stage =
|
||||
// Determine whether stage can transition based on TransitionStyle
|
||||
if let Hold(Holding) | Timed(Success) = transition_style {
|
||||
// Determine what stage to transition to
|
||||
match self.stage {
|
||||
Stage::First => Some(Stage::Second),
|
||||
Stage::Second => Some(Stage::Third),
|
||||
Stage::Third => None,
|
||||
}
|
||||
}
|
||||
// Player messed up inputs, don't transition
|
||||
else { None };
|
||||
|
||||
update.vel.0 = Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * 5.0;
|
||||
|
||||
if let Some(stage) = next_stage {
|
||||
CharacterState::TripleStrike(Data {
|
||||
base_damage: self.base_damage,
|
||||
stage,
|
||||
stage_time_active: Duration::default(),
|
||||
stage_exhausted: false,
|
||||
initialized,
|
||||
transition_style: match transition_style {
|
||||
Hold(_) => Hold(Holding),
|
||||
Timed(_) => Timed(NotPressed),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
// Make sure attack component is removed
|
||||
data.updater.remove::<Attacking>(data.entity);
|
||||
// Done
|
||||
CharacterState::Wielding
|
||||
}
|
||||
} else {
|
||||
CharacterState::TripleStrike(Data {
|
||||
base_damage: self.base_damage,
|
||||
stage: self.stage,
|
||||
stage_time_active,
|
||||
stage_exhausted: self.stage_exhausted,
|
||||
initialized,
|
||||
transition_style,
|
||||
})
|
||||
};
|
||||
|
||||
// Grant energy on successful hit
|
||||
if let Some(attack) = data.attacking {
|
||||
if attack.applied && attack.hit_count > 0 {
|
||||
data.updater.remove::<Attacking>(data.entity);
|
||||
update.energy.change_by(50, EnergySource::HitEnemy);
|
||||
}
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ use crate::{
|
||||
sys::{character_behavior::JoinData, phys::GRAVITY},
|
||||
util::Dir,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
|
||||
@ -89,6 +90,21 @@ fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
|
||||
handle_orientation(data, update, data.body.base_ori_rate());
|
||||
}
|
||||
|
||||
/// Similar to basic_move function, but with forced forward movement
|
||||
pub fn forward_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, forward: f32) {
|
||||
let accel = if data.physics.on_ground {
|
||||
data.body.base_accel()
|
||||
} else {
|
||||
BASE_HUMANOID_AIR_ACCEL
|
||||
};
|
||||
|
||||
update.vel.0 += Vec2::broadcast(data.dt.0)
|
||||
* accel
|
||||
* (data.inputs.move_dir * efficiency + (*update.ori.0).xy() * forward);
|
||||
|
||||
handle_orientation(data, update, data.body.base_ori_rate() * efficiency);
|
||||
}
|
||||
|
||||
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() {
|
||||
@ -330,3 +346,21 @@ pub fn unwrap_tool_data<'a>(data: &'a JoinData) -> Option<&'a Tool> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_interrupt(data: &JoinData, update: &mut StateUpdate) {
|
||||
handle_ability1_input(data, update);
|
||||
handle_ability2_input(data, update);
|
||||
handle_ability3_input(data, update);
|
||||
handle_dodge_input(data, update);
|
||||
}
|
||||
|
||||
/// Determines what portion a state is in. Used in all attacks (eventually). Is
|
||||
/// used to control aspects of animation code, as well as logic within the
|
||||
/// character states.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum StageSection {
|
||||
Buildup,
|
||||
Swing,
|
||||
Recover,
|
||||
Charge,
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ impl<'a> System<'a> for Sys {
|
||||
CharacterState::Roll(data) => data.handle_event(&j, action),
|
||||
CharacterState::Wielding => states::wielding::Data.handle_event(&j, action),
|
||||
CharacterState::Equipping(data) => data.handle_event(&j, action),
|
||||
CharacterState::TripleStrike(data) => data.handle_event(&j, action),
|
||||
CharacterState::ComboMelee(data) => data.handle_event(&j, action),
|
||||
CharacterState::BasicMelee(data) => data.handle_event(&j, action),
|
||||
CharacterState::BasicRanged(data) => data.handle_event(&j, action),
|
||||
CharacterState::Boost(data) => data.handle_event(&j, action),
|
||||
@ -279,7 +279,7 @@ impl<'a> System<'a> for Sys {
|
||||
CharacterState::Roll(data) => data.behavior(&j),
|
||||
CharacterState::Wielding => states::wielding::Data.behavior(&j),
|
||||
CharacterState::Equipping(data) => data.behavior(&j),
|
||||
CharacterState::TripleStrike(data) => data.behavior(&j),
|
||||
CharacterState::ComboMelee(data) => data.behavior(&j),
|
||||
CharacterState::BasicMelee(data) => data.behavior(&j),
|
||||
CharacterState::BasicRanged(data) => data.behavior(&j),
|
||||
CharacterState::Boost(data) => data.behavior(&j),
|
||||
|
@ -153,10 +153,11 @@ impl<'a> System<'a> for Sys {
|
||||
});
|
||||
}
|
||||
if attack.knockback != 0.0 && damage.healthchange != 0.0 {
|
||||
let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
|
||||
server_emitter.emit(ServerEvent::Knockback {
|
||||
entity: b,
|
||||
impulse: attack.knockback
|
||||
* *Dir::slerp(ori.0, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5),
|
||||
* *Dir::slerp(kb_dir, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5),
|
||||
});
|
||||
}
|
||||
attack.hit_count += 1;
|
||||
|
@ -156,6 +156,9 @@ impl<'a> System<'a> for Sys {
|
||||
let z_limits = collider.map(|c| c.get_z_limits()).unwrap_or((-0.5, 0.5));
|
||||
let mass = mass.map(|m| m.0).unwrap_or(scale);
|
||||
|
||||
// Resets touch_entities in physics
|
||||
physics.touch_entities.clear();
|
||||
|
||||
// Group to ignore collisions with
|
||||
let ignore_group = projectile
|
||||
.filter(|p| p.ignore_group)
|
||||
|
@ -110,7 +110,7 @@ impl<'a> System<'a> for Sys {
|
||||
| CharacterState::DashMelee { .. }
|
||||
| CharacterState::LeapMelee { .. }
|
||||
| CharacterState::SpinMelee { .. }
|
||||
| CharacterState::TripleStrike { .. }
|
||||
| CharacterState::ComboMelee { .. }
|
||||
| CharacterState::BasicRanged { .. }
|
||||
| CharacterState::ChargedRanged { .. }
|
||||
| CharacterState::GroundShockwave { .. } => {
|
||||
|
@ -621,7 +621,8 @@ fn handle_spawn(
|
||||
.create_npc(
|
||||
pos,
|
||||
comp::Stats::new(get_npc_name(id).into(), body),
|
||||
LoadoutBuilder::build_loadout(body, alignment, None).build(),
|
||||
LoadoutBuilder::build_loadout(body, alignment, None, false)
|
||||
.build(),
|
||||
body,
|
||||
)
|
||||
.with(comp::Vel(vel))
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::SysTimer;
|
||||
use crate::{chunk_generator::ChunkGenerator, client::Client, Tick};
|
||||
use common::{
|
||||
comp::{self, bird_medium, Alignment, CharacterAbility, Player, Pos},
|
||||
comp::{self, bird_medium, Alignment, Player, Pos},
|
||||
event::{EventBus, ServerEvent},
|
||||
generation::get_npc_name,
|
||||
msg::ServerMsg,
|
||||
@ -13,7 +13,7 @@ use common::{
|
||||
};
|
||||
use rand::Rng;
|
||||
use specs::{Join, Read, ReadStorage, System, Write, WriteExpect, WriteStorage};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use std::sync::Arc;
|
||||
use vek::*;
|
||||
|
||||
/// This system will handle loading generated chunks and unloading
|
||||
@ -120,7 +120,9 @@ impl<'a> System<'a> for Sys {
|
||||
// let damage = stats.level.level() as i32; TODO: Make NPC base damage
|
||||
// non-linearly depend on their level
|
||||
|
||||
let mut loadout = LoadoutBuilder::build_loadout(body, alignment, main_tool).build();
|
||||
let loadout =
|
||||
LoadoutBuilder::build_loadout(body, alignment, main_tool, entity.is_giant)
|
||||
.build();
|
||||
|
||||
let mut scale = entity.scale;
|
||||
|
||||
@ -151,53 +153,6 @@ impl<'a> System<'a> for Sys {
|
||||
body,
|
||||
);
|
||||
}
|
||||
loadout = comp::Loadout {
|
||||
active_item: Some(comp::ItemConfig {
|
||||
item: comp::Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.sword.zweihander_sword_0",
|
||||
),
|
||||
ability1: Some(CharacterAbility::BasicMelee {
|
||||
energy_cost: 0,
|
||||
buildup_duration: Duration::from_millis(800),
|
||||
recover_duration: Duration::from_millis(200),
|
||||
base_healthchange: -100,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 60.0,
|
||||
}),
|
||||
ability2: None,
|
||||
ability3: None,
|
||||
block_ability: None,
|
||||
dodge_ability: None,
|
||||
}),
|
||||
second_item: None,
|
||||
shoulder: Some(comp::Item::new_from_asset_expect(
|
||||
"common.items.armor.shoulder.plate_0",
|
||||
)),
|
||||
chest: Some(comp::Item::new_from_asset_expect(
|
||||
"common.items.armor.chest.plate_green_0",
|
||||
)),
|
||||
belt: Some(comp::Item::new_from_asset_expect(
|
||||
"common.items.armor.belt.plate_0",
|
||||
)),
|
||||
hand: Some(comp::Item::new_from_asset_expect(
|
||||
"common.items.armor.hand.plate_0",
|
||||
)),
|
||||
pants: Some(comp::Item::new_from_asset_expect(
|
||||
"common.items.armor.pants.plate_green_0",
|
||||
)),
|
||||
foot: Some(comp::Item::new_from_asset_expect(
|
||||
"common.items.armor.foot.plate_0",
|
||||
)),
|
||||
back: None,
|
||||
ring: None,
|
||||
neck: None,
|
||||
lantern: None,
|
||||
glider: None,
|
||||
head: None,
|
||||
tabard: None,
|
||||
};
|
||||
|
||||
stats.level.set_level(rand::thread_rng().gen_range(30, 35));
|
||||
scale = 2.0 + rand::random::<f32>();
|
||||
}
|
||||
|
@ -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 = []
|
||||
|
@ -2,13 +2,22 @@ use super::{
|
||||
super::{vek::*, Animation},
|
||||
CharacterSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::comp::item::{Hands, ToolKind};
|
||||
use common::{
|
||||
comp::item::{Hands, ToolKind},
|
||||
states::utils::StageSection,
|
||||
};
|
||||
use std::f32::consts::PI;
|
||||
|
||||
pub struct AlphaAnimation;
|
||||
|
||||
impl Animation for AlphaAnimation {
|
||||
type Dependency = (Option<ToolKind>, Option<ToolKind>, f32, f64);
|
||||
type Dependency = (
|
||||
Option<ToolKind>,
|
||||
Option<ToolKind>,
|
||||
f32,
|
||||
f64,
|
||||
Option<StageSection>,
|
||||
);
|
||||
type Skeleton = CharacterSkeleton;
|
||||
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
@ -18,7 +27,7 @@ impl Animation for AlphaAnimation {
|
||||
#[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,
|
||||
@ -61,74 +70,77 @@ impl Animation for AlphaAnimation {
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * lab as f32 * 4.0).sin());
|
||||
|
||||
let movement = anim_time as f32 * 1.0;
|
||||
let test = (anim_time as f32 * 1.75).sin();
|
||||
|
||||
if let Some(ToolKind::Sword(_)) = active_tool_kind {
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2);
|
||||
next.l_hand.scale = Vec3::one() * 1.04;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -0.5);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(0.0, 0.0, 2.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.1)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
|
||||
next.head.position = Vec3::new(0.0, skeleton_attr.head.0 + 0.0, skeleton_attr.head.1);
|
||||
|
||||
if let Some(stage_section) = stage_section {
|
||||
match stage_section {
|
||||
StageSection::Buildup => {
|
||||
//println!("{:.3} build", anim_time);
|
||||
next.control.position =
|
||||
Vec3::new(-7.0, 7.0 + movement * -4.0, 2.0 + movement * 1.0);
|
||||
next.control.orientation = Quaternion::rotation_x(movement * -0.5)
|
||||
* Quaternion::rotation_y(movement * -1.0)
|
||||
* Quaternion::rotation_z(movement * -1.2);
|
||||
|
||||
next.chest.orientation = Quaternion::rotation_z(movement * 1.5);
|
||||
next.head.orientation = Quaternion::rotation_z(movement * -0.9);
|
||||
},
|
||||
StageSection::Swing => {
|
||||
//println!("{:.3} swing", anim_time);
|
||||
next.control.position = Vec3::new(-7.0, 3.0 + movement * 16.0, 3.0);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(-0.5 + movement * -1.0 * 0.0)
|
||||
* Quaternion::rotation_y(-1.0 + movement * -0.6)
|
||||
* Quaternion::rotation_z(-1.2 + movement * 1.3);
|
||||
|
||||
next.chest.orientation = Quaternion::rotation_z(1.5 + test * -3.0);
|
||||
next.head.orientation = Quaternion::rotation_z(-0.9 + test * 2.5);
|
||||
//next.head.orientation = Quaternion::rotation_z(-test
|
||||
// * 0.8); next.chest.
|
||||
// orientation = Quaternion::rotation_x(test * 0.15)
|
||||
//* Quaternion::rotation_y(movement * 0.3)
|
||||
//* Quaternion::rotation_z(movement * 1.5);
|
||||
//next.belt.orientation = Quaternion::rotation_z(test2
|
||||
// * 0.5); next.shorts.
|
||||
// orientation = Quaternion::rotation_z(test2 * 1.5);
|
||||
// next.torso.orientation = Quaternion::rotation_z(test2
|
||||
// * 7.2);
|
||||
},
|
||||
StageSection::Recover => {
|
||||
//println!("{:.3} recover", anim_time);
|
||||
next.control.position = Vec3::new(-7.0, 15.0, 2.0);
|
||||
next.control.orientation = Quaternion::rotation_x(-0.5)
|
||||
* Quaternion::rotation_y(-1.57 + movement * 1.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.control.scale = Vec3::one();
|
||||
next.chest.orientation = Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(-1.57 + movement * 0.5);
|
||||
|
||||
next.head.orientation = Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(1.57 + movement * -0.5);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match active_tool_kind {
|
||||
//TODO: Inventory
|
||||
Some(ToolKind::Sword(_)) => {
|
||||
next.head.position =
|
||||
Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
next.head.orientation = Quaternion::rotation_z(slow * -0.25)
|
||||
* Quaternion::rotation_x(0.0 + slow * 0.15)
|
||||
* Quaternion::rotation_y(slow * -0.15);
|
||||
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
|
||||
|
||||
next.chest.position = Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1);
|
||||
next.chest.orientation = Quaternion::rotation_z(slow * 0.4)
|
||||
* Quaternion::rotation_x(0.0 + slow * -0.2)
|
||||
* Quaternion::rotation_y(slow * 0.2);
|
||||
next.chest.scale = Vec3::one();
|
||||
|
||||
next.belt.position = Vec3::new(0.0, skeleton_attr.belt.0, skeleton_attr.belt.1);
|
||||
next.belt.orientation = next.chest.orientation * -0.3;
|
||||
|
||||
next.shorts.position =
|
||||
Vec3::new(0.0, skeleton_attr.shorts.0, skeleton_attr.shorts.1);
|
||||
next.shorts.orientation = next.chest.orientation * -0.45;
|
||||
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.l_hand.scale = Vec3::one() * 1.05;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -5.5);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.3)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
|
||||
next.control.position = Vec3::new(-10.0 + push * 5.0, 6.0 + push * 5.0, 2.0);
|
||||
next.control.orientation = Quaternion::rotation_x(-1.4 + slow * 0.4)
|
||||
* Quaternion::rotation_y(slow * -1.3)
|
||||
* Quaternion::rotation_z(1.4 + slow * -0.5);
|
||||
next.control.scale = Vec3::one();
|
||||
|
||||
next.l_foot.position = Vec3::new(
|
||||
-skeleton_attr.foot.0,
|
||||
slow * -3.0 + quick * 3.0 - 4.0,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(slow * 0.6)
|
||||
* Quaternion::rotation_y((slow * -0.2).max(0.0));
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position = Vec3::new(
|
||||
skeleton_attr.foot.0,
|
||||
slow * 3.0 + quick * -3.0 + 5.0,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(slow * -0.6)
|
||||
* Quaternion::rotation_y((slow * 0.2).min(0.0));
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.lantern.orientation =
|
||||
Quaternion::rotation_x(slow * -0.7 + 0.4) * Quaternion::rotation_y(slow * 0.4);
|
||||
next.hold.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler;
|
||||
next.torso.orientation = Quaternion::rotation_z(0.0)
|
||||
* Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
},
|
||||
Some(ToolKind::Dagger(_)) => {
|
||||
next.head.position =
|
||||
Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
|
@ -2,12 +2,21 @@ use super::{
|
||||
super::{vek::*, Animation},
|
||||
CharacterSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::comp::item::{Hands, ToolKind};
|
||||
use common::{
|
||||
comp::item::{Hands, ToolKind},
|
||||
states::utils::StageSection,
|
||||
};
|
||||
|
||||
pub struct BetaAnimation;
|
||||
|
||||
impl Animation for BetaAnimation {
|
||||
type Dependency = (Option<ToolKind>, Option<ToolKind>, f32, f64);
|
||||
type Dependency = (
|
||||
Option<ToolKind>,
|
||||
Option<ToolKind>,
|
||||
f32,
|
||||
f64,
|
||||
Option<StageSection>,
|
||||
);
|
||||
type Skeleton = CharacterSkeleton;
|
||||
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
@ -16,7 +25,7 @@ impl Animation for BetaAnimation {
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_beta")]
|
||||
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,
|
||||
@ -43,60 +52,175 @@ impl Animation for BetaAnimation {
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * lab as f32 * 14.0).sin());
|
||||
|
||||
if let Some(
|
||||
ToolKind::Axe(_) | ToolKind::Hammer(_) | ToolKind::Sword(_) | ToolKind::Dagger(_),
|
||||
) = active_tool_kind
|
||||
{
|
||||
//INTENTION: SWORD
|
||||
next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
next.head.orientation = Quaternion::rotation_z(slow * -0.18)
|
||||
* Quaternion::rotation_x(-0.1 + slow * -0.28)
|
||||
* Quaternion::rotation_y(0.2 + slow * 0.18);
|
||||
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
|
||||
let recover = (anim_time as f32 * 8.0).sin();
|
||||
|
||||
next.chest.position = Vec3::new(0.0 + foot * 2.0, 0.0, 7.0);
|
||||
next.chest.orientation = Quaternion::rotation_z(slow * 0.2)
|
||||
* Quaternion::rotation_x(slow * 0.2)
|
||||
* Quaternion::rotation_y(slow * -0.1);
|
||||
let movement = anim_time as f32 * 1.0;
|
||||
let stab = (anim_time as f32 * 2.5).sin();
|
||||
|
||||
next.belt.position = Vec3::new(0.0, 0.0, -2.0);
|
||||
next.belt.orientation = Quaternion::rotation_z(slow * 0.1)
|
||||
* Quaternion::rotation_x(slow * 0.1)
|
||||
* Quaternion::rotation_y(slow * -0.04);
|
||||
|
||||
next.shorts.position = Vec3::new(0.0, 0.0, -5.0);
|
||||
next.shorts.orientation = Quaternion::rotation_z(slow * 0.1)
|
||||
* Quaternion::rotation_x(slow * 0.1)
|
||||
* Quaternion::rotation_y(slow * -0.05);
|
||||
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
if let Some(ToolKind::Sword(_)) = active_tool_kind {
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2);
|
||||
next.l_hand.scale = Vec3::one() * 1.04;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -5.5);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -0.5);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(0.0, 6.0, -1.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.3);
|
||||
next.main.position = Vec3::new(0.0, 0.0, 2.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.1)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
|
||||
next.control.position = Vec3::new(-8.0 + slow * 1.5, 1.5 + slow * 1.0, 0.0);
|
||||
next.control.orientation = Quaternion::rotation_x(-1.4)
|
||||
* Quaternion::rotation_y(slow * 2.0 + 0.7)
|
||||
* Quaternion::rotation_z(1.7 - slow * 0.4 + fast * 0.6);
|
||||
next.control.scale = Vec3::one();
|
||||
next.l_foot.position = Vec3::new(
|
||||
-skeleton_attr.foot.0,
|
||||
footquick * -9.5,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.l_foot.orientation =
|
||||
Quaternion::rotation_x(footquick * 0.3) * Quaternion::rotation_y(footquick * -0.6);
|
||||
next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
|
||||
next.r_foot.position =
|
||||
Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation =
|
||||
Quaternion::rotation_x(footquick * -0.3) * Quaternion::rotation_y(footquick * 0.2);
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler;
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
if let Some(stage_section) = stage_section {
|
||||
match stage_section {
|
||||
StageSection::Buildup => {
|
||||
//println!("{:.3} recover", anim_time);
|
||||
next.control.position = Vec3::new(
|
||||
-8.0 + movement * -5.0,
|
||||
1.0 - recover * 0.8 + movement * 2.0,
|
||||
2.0 - recover * 0.4,
|
||||
);
|
||||
next.control.orientation = Quaternion::rotation_x(-1.57)
|
||||
* Quaternion::rotation_y(0.0 + movement * 1.5)
|
||||
* Quaternion::rotation_z(1.0);
|
||||
next.chest.orientation = Quaternion::rotation_y(-0.1)
|
||||
* Quaternion::rotation_z(0.4 + movement * 1.5);
|
||||
next.head.orientation = Quaternion::rotation_y(0.1)
|
||||
* Quaternion::rotation_z(-0.1 + movement * -1.1);
|
||||
},
|
||||
StageSection::Swing => {
|
||||
//println!("{:.3} swing", anim_time);
|
||||
next.control.position =
|
||||
Vec3::new(-8.0 + stab * 30.0, 6.0 + movement * 2.0, 6.0);
|
||||
next.control.orientation = Quaternion::rotation_x(-1.57)
|
||||
* Quaternion::rotation_y(1.5 + stab * 0.5)
|
||||
* Quaternion::rotation_z(1.0 + stab * 1.0);
|
||||
next.chest.orientation = Quaternion::rotation_y(-0.1)
|
||||
* Quaternion::rotation_z(1.9 + stab * -0.5);
|
||||
next.head.orientation = Quaternion::rotation_y(0.1)
|
||||
* Quaternion::rotation_z(-1.2 + stab * -0.5);
|
||||
},
|
||||
StageSection::Recover => {
|
||||
next.control.position = Vec3::new(10.0 + movement * -5.0, 8.0, 6.0);
|
||||
next.control.orientation = Quaternion::rotation_x(-1.57)
|
||||
* Quaternion::rotation_y(2.0)
|
||||
* Quaternion::rotation_z(2.0);
|
||||
next.chest.orientation = Quaternion::rotation_y(-0.1)
|
||||
* Quaternion::rotation_z(1.4 + movement * 1.0);
|
||||
next.head.orientation =
|
||||
Quaternion::rotation_y(0.1) * Quaternion::rotation_z(-1.5);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match active_tool_kind {
|
||||
Some(ToolKind::Hammer(_)) => {
|
||||
next.head.position =
|
||||
Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
next.head.orientation = Quaternion::rotation_z(slow * -0.18)
|
||||
* Quaternion::rotation_x(-0.1 + slow * -0.28)
|
||||
* Quaternion::rotation_y(0.2 + slow * 0.18);
|
||||
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
|
||||
|
||||
next.chest.position = Vec3::new(0.0 + foot * 2.0, 0.0, 7.0);
|
||||
next.chest.orientation = Quaternion::rotation_z(slow * 0.2)
|
||||
* Quaternion::rotation_x(slow * 0.2)
|
||||
* Quaternion::rotation_y(slow * -0.1);
|
||||
|
||||
next.belt.position = Vec3::new(0.0, 0.0, -2.0);
|
||||
next.belt.orientation = Quaternion::rotation_z(slow * 0.1)
|
||||
* Quaternion::rotation_x(slow * 0.1)
|
||||
* Quaternion::rotation_y(slow * -0.04);
|
||||
|
||||
next.shorts.position = Vec3::new(0.0, 0.0, -5.0);
|
||||
next.shorts.orientation = Quaternion::rotation_z(slow * 0.1)
|
||||
* Quaternion::rotation_x(slow * 0.1)
|
||||
* Quaternion::rotation_y(slow * -0.05);
|
||||
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.l_hand.scale = Vec3::one() * 1.04;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -5.5);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(0.0, 6.0, -1.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.3);
|
||||
|
||||
next.control.position = Vec3::new(-8.0 + slow * 1.5, 1.5 + slow * 1.0, 0.0);
|
||||
next.control.orientation = Quaternion::rotation_x(-1.4)
|
||||
* Quaternion::rotation_y(slow * 2.0 + 0.7)
|
||||
* Quaternion::rotation_z(1.7 - slow * 0.4 + fast * 0.6);
|
||||
next.control.scale = Vec3::one();
|
||||
next.l_foot.position = Vec3::new(
|
||||
-skeleton_attr.foot.0,
|
||||
footquick * -9.5,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(footquick * 0.3)
|
||||
* Quaternion::rotation_y(footquick * -0.6);
|
||||
|
||||
next.r_foot.position =
|
||||
Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(footquick * -0.3)
|
||||
* Quaternion::rotation_y(footquick * 0.2);
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler;
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
},
|
||||
Some(ToolKind::Axe(_)) => {
|
||||
next.head.position =
|
||||
Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
next.head.orientation = Quaternion::rotation_z(slow * -0.18)
|
||||
* Quaternion::rotation_x(-0.1 + slow * -0.28)
|
||||
* Quaternion::rotation_y(0.2 + slow * 0.18);
|
||||
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
|
||||
|
||||
next.chest.position = Vec3::new(0.0 + foot * 2.0, 0.0, 7.0);
|
||||
next.chest.orientation = Quaternion::rotation_z(slow * 0.2)
|
||||
* Quaternion::rotation_x(slow * 0.2)
|
||||
* Quaternion::rotation_y(slow * -0.1);
|
||||
|
||||
next.belt.position = Vec3::new(0.0, 0.0, -2.0);
|
||||
next.belt.orientation = Quaternion::rotation_z(slow * 0.1)
|
||||
* Quaternion::rotation_x(slow * 0.1)
|
||||
* Quaternion::rotation_y(slow * -0.04);
|
||||
|
||||
next.shorts.position = Vec3::new(0.0, 0.0, -5.0);
|
||||
next.shorts.orientation = Quaternion::rotation_z(slow * 0.1)
|
||||
* Quaternion::rotation_x(slow * 0.1)
|
||||
* Quaternion::rotation_y(slow * -0.05);
|
||||
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.l_hand.scale = Vec3::one() * 1.04;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -5.5);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(0.0, 6.0, -1.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.3);
|
||||
|
||||
next.control.position = Vec3::new(-8.0 + slow * 1.5, 1.5 + slow * 1.0, 0.0);
|
||||
next.control.orientation = Quaternion::rotation_x(-1.4)
|
||||
* Quaternion::rotation_y(slow * 2.0 + 0.7)
|
||||
* Quaternion::rotation_z(1.7 - slow * 0.4 + fast * 0.6);
|
||||
next.control.scale = Vec3::one();
|
||||
next.l_foot.position = Vec3::new(
|
||||
-skeleton_attr.foot.0,
|
||||
footquick * -9.5,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(footquick * 0.3)
|
||||
* Quaternion::rotation_y(footquick * -0.6);
|
||||
|
||||
next.r_foot.position =
|
||||
Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(footquick * -0.3)
|
||||
* Quaternion::rotation_y(footquick * 0.2);
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler;
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
next.l_shoulder.position = Vec3::new(
|
||||
|
@ -2,7 +2,11 @@ use super::{
|
||||
super::{vek::*, Animation},
|
||||
CharacterSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::comp::item::{Hands, ToolKind};
|
||||
use common::{
|
||||
comp::item::{Hands, ToolKind},
|
||||
states::utils::StageSection,
|
||||
};
|
||||
use std::f32::consts::PI;
|
||||
|
||||
pub struct Input {
|
||||
pub attack: bool,
|
||||
@ -10,7 +14,12 @@ pub struct Input {
|
||||
pub struct DashAnimation;
|
||||
|
||||
impl Animation for DashAnimation {
|
||||
type Dependency = (Option<ToolKind>, Option<ToolKind>, f64);
|
||||
type Dependency = (
|
||||
Option<ToolKind>,
|
||||
Option<ToolKind>,
|
||||
f64,
|
||||
Option<StageSection>,
|
||||
);
|
||||
type Skeleton = CharacterSkeleton;
|
||||
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
@ -20,7 +29,7 @@ impl Animation for DashAnimation {
|
||||
#[allow(clippy::single_match)] // TODO: Pending review in #587
|
||||
fn update_skeleton_inner(
|
||||
skeleton: &Self::Skeleton,
|
||||
(active_tool_kind, second_tool_kind, _global_time): Self::Dependency,
|
||||
(active_tool_kind, second_tool_kind, _global_time, stage_section): Self::Dependency,
|
||||
anim_time: f64,
|
||||
rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
@ -29,58 +38,150 @@ impl Animation for DashAnimation {
|
||||
let mut next = (*skeleton).clone();
|
||||
let lab = 1.0;
|
||||
|
||||
let foot = (((5.0)
|
||||
/ (1.1 + 3.9 * ((anim_time as f32 * lab as f32 * 25.0).sin()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * lab as f32 * 25.0).sin());
|
||||
|
||||
let slow = (((5.0)
|
||||
/ (1.1 + 3.9 * ((anim_time as f32 * lab as f32 * 12.4).sin()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * lab as f32 * 12.4).sin());
|
||||
|
||||
let short = (((5.0)
|
||||
/ (1.5 + 3.5 * ((anim_time as f32 * lab as f32 * 5.0).sin()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * lab as f32 * 5.0).sin());
|
||||
let foothoril = (anim_time as f32 * 5.0 * lab as f32 + PI * 1.45).sin();
|
||||
let foothorir = (anim_time as f32 * 5.0 * lab as f32 + PI * (0.45)).sin();
|
||||
|
||||
let footvertl = (anim_time as f32 * 5.0 * lab as f32).sin();
|
||||
let footvertr = (anim_time as f32 * 5.0 * lab as f32 + PI).sin();
|
||||
|
||||
let footrotl = (((1.0)
|
||||
/ (0.05
|
||||
+ (0.95)
|
||||
* ((anim_time as f32 * 5.0 * lab as f32 + PI * 1.4).sin()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * 5.0 * lab as f32 + PI * 1.4).sin());
|
||||
|
||||
let footrotr = (((1.0)
|
||||
/ (0.05
|
||||
+ (0.95)
|
||||
* ((anim_time as f32 * 5.0 * lab as f32 + PI * 0.4).sin()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * 5.0 * lab as f32 + PI * 0.4).sin());
|
||||
|
||||
let shortalt = (anim_time as f32 * lab as f32 * 5.0 + PI / 2.0).sin();
|
||||
|
||||
let movement = (anim_time as f32 * 1.0).min(1.0);
|
||||
|
||||
next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2);
|
||||
next.l_hand.scale = Vec3::one() * 1.04;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -0.5);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(0.0, 0.0, 2.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.1)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
|
||||
match active_tool_kind {
|
||||
//TODO: Inventory
|
||||
Some(ToolKind::Sword(_)) => {
|
||||
next.head.position = Vec3::new(
|
||||
0.0,
|
||||
-2.0 + skeleton_attr.head.0,
|
||||
-2.0 + skeleton_attr.head.1,
|
||||
);
|
||||
next.head.orientation = Quaternion::rotation_z(0.0)
|
||||
* Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
|
||||
if let Some(stage_section) = stage_section {
|
||||
match stage_section {
|
||||
StageSection::Buildup => {
|
||||
next.head.orientation = Quaternion::rotation_z(movement * -0.9);
|
||||
|
||||
next.chest.position = Vec3::new(0.0, 0.0, 7.0 + slow * 2.0);
|
||||
next.chest.orientation =
|
||||
Quaternion::rotation_x(-0.5) * Quaternion::rotation_z(-0.7);
|
||||
next.chest.orientation = Quaternion::rotation_z(movement * 1.1);
|
||||
|
||||
next.belt.position = Vec3::new(0.0, 1.0, -1.0);
|
||||
next.belt.orientation = Quaternion::rotation_x(0.2) * Quaternion::rotation_z(0.2);
|
||||
next.control.position = Vec3::new(-7.0 + movement * -5.0, 7.0, 2.0);
|
||||
next.control.orientation = Quaternion::rotation_x(movement * -1.0)
|
||||
* Quaternion::rotation_y(movement * 1.5)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.control.scale = Vec3::one();
|
||||
next.l_foot.position = Vec3::new(
|
||||
-skeleton_attr.foot.0,
|
||||
skeleton_attr.foot.1 + movement * -12.0,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(movement * -1.0);
|
||||
next.r_foot.position = Vec3::new(
|
||||
skeleton_attr.foot.0,
|
||||
skeleton_attr.foot.1,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
},
|
||||
StageSection::Charge => {
|
||||
next.head.position = Vec3::new(
|
||||
0.0,
|
||||
-2.0 + skeleton_attr.head.0,
|
||||
skeleton_attr.head.1 + movement * 1.0,
|
||||
);
|
||||
|
||||
next.shorts.position = Vec3::new(0.0, 3.0, -3.0);
|
||||
next.shorts.orientation = Quaternion::rotation_x(0.4) * Quaternion::rotation_z(0.3);
|
||||
next.head.orientation = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(movement * -0.3)
|
||||
* Quaternion::rotation_z(-0.9 + movement * -0.2 + short * -0.05);
|
||||
next.chest.position = Vec3::new(
|
||||
0.0,
|
||||
skeleton_attr.chest.0,
|
||||
skeleton_attr.chest.1 + 2.0 + shortalt * -2.5,
|
||||
);
|
||||
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.l_hand.scale = Vec3::one() * 1.04;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -5.5);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(0.0, 6.0, -1.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.3);
|
||||
next.main.scale = Vec3::one();
|
||||
next.chest.orientation = Quaternion::rotation_x(movement * -0.4)
|
||||
* Quaternion::rotation_y(movement * -0.2)
|
||||
* Quaternion::rotation_z(1.1);
|
||||
|
||||
next.control.position = Vec3::new(-8.0 - slow * 0.5, 3.0 - foot * 0.6, 3.0);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(-0.3) * Quaternion::rotation_z(1.1 + slow * 0.2);
|
||||
next.control.scale = Vec3::one();
|
||||
next.l_foot.position = Vec3::new(-1.4, foot * 3.0 + 2.0, skeleton_attr.foot.2);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(foot * -0.4 - 0.8);
|
||||
next.control.position =
|
||||
Vec3::new(-13.0, 7.0 + movement * -2.0, 2.0 + movement * 2.0);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(-1.0) * Quaternion::rotation_y(1.5);
|
||||
next.control.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position = Vec3::new(5.4, foot * -3.0 - 1.0, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(foot * 0.4 - 0.8);
|
||||
next.shorts.orientation = Quaternion::rotation_z(short * 0.25);
|
||||
next.belt.orientation = Quaternion::rotation_z(short * 0.1);
|
||||
next.l_foot.position = Vec3::new(
|
||||
2.0 - skeleton_attr.foot.0,
|
||||
skeleton_attr.foot.1 + foothoril * -7.5,
|
||||
2.0 + skeleton_attr.foot.2 + ((footvertl * -4.0).max(-1.0)),
|
||||
);
|
||||
next.l_foot.orientation =
|
||||
Quaternion::rotation_x(-0.6 + footrotl * -0.6)
|
||||
* Quaternion::rotation_z(-0.2);
|
||||
|
||||
next.r_foot.position = Vec3::new(
|
||||
2.0 + skeleton_attr.foot.0,
|
||||
skeleton_attr.foot.1 + foothorir * -7.5,
|
||||
2.0 + skeleton_attr.foot.2 + ((footvertr * -4.0).max(-1.0)),
|
||||
);
|
||||
next.r_foot.orientation =
|
||||
Quaternion::rotation_x(-0.6 + footrotr * -0.6)
|
||||
* Quaternion::rotation_z(-0.2);
|
||||
},
|
||||
StageSection::Swing => {
|
||||
next.head.orientation = Quaternion::rotation_y(0.2 + movement * -0.2)
|
||||
* Quaternion::rotation_z(-1.1 + movement * 1.8);
|
||||
|
||||
next.chest.orientation = Quaternion::rotation_y(-0.2 + movement * 0.3)
|
||||
* Quaternion::rotation_z(1.1 + movement * -2.2);
|
||||
|
||||
next.control.position = Vec3::new(-13.0 + movement * -2.0, 5.0, 4.0);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(-1.0 + movement * -0.5)
|
||||
* Quaternion::rotation_y(1.5 + movement * -2.5);
|
||||
next.control.scale = Vec3::one();
|
||||
},
|
||||
StageSection::Recover => {
|
||||
next.head.orientation = Quaternion::rotation_z(0.7);
|
||||
|
||||
next.chest.orientation = Quaternion::rotation_z(-1.1);
|
||||
|
||||
next.control.position = Vec3::new(-15.0, 5.0, 2.0);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(-1.5) * Quaternion::rotation_y(-1.0);
|
||||
next.control.scale = Vec3::one();
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(ToolKind::Dagger(_)) => {
|
||||
next.head.position = Vec3::new(
|
||||
@ -113,15 +214,15 @@ impl Animation for DashAnimation {
|
||||
next.main.orientation = Quaternion::rotation_x(-0.3);
|
||||
next.main.scale = Vec3::one();
|
||||
|
||||
next.control.position = Vec3::new(-8.0 - slow * 0.5, 3.0 - foot * 0.6, 3.0);
|
||||
next.control.position = Vec3::new(-8.0 - slow * 0.5, 3.0, 3.0);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(-0.3) * Quaternion::rotation_z(1.1 + slow * 0.2);
|
||||
next.control.scale = Vec3::one();
|
||||
next.l_foot.position = Vec3::new(-1.4, foot * 3.0 + 2.0, skeleton_attr.foot.2);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(foot * -0.4 - 0.8);
|
||||
next.l_foot.position = Vec3::new(-1.4, 2.0, skeleton_attr.foot.2);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(-0.8);
|
||||
|
||||
next.r_foot.position = Vec3::new(5.4, foot * -3.0 - 1.0, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(foot * 0.4 - 0.8);
|
||||
next.r_foot.position = Vec3::new(5.4, -1.0, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(-0.8);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
@ -172,11 +273,11 @@ impl Animation for DashAnimation {
|
||||
next.second.orientation = Quaternion::rotation_x(-0.3);
|
||||
next.second.scale = Vec3::one();
|
||||
|
||||
next.l_foot.position = Vec3::new(-1.4, foot * 3.0 + 2.0, skeleton_attr.foot.2);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(foot * -0.4 - 0.8);
|
||||
next.l_foot.position = Vec3::new(-1.4, 2.0, skeleton_attr.foot.2);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(-0.8);
|
||||
|
||||
next.r_foot.position = Vec3::new(5.4, foot * -3.0 - 1.0, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(foot * 0.4 - 0.8);
|
||||
next.r_foot.position = Vec3::new(5.4, -1.0, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(-0.8);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
@ -190,9 +291,6 @@ impl Animation for DashAnimation {
|
||||
Quaternion::rotation_x(slow * -0.7 + 0.4) * Quaternion::rotation_y(slow * 0.4);
|
||||
next.hold.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler;
|
||||
next.torso.orientation =
|
||||
Quaternion::rotation_z(0.0) * Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
|
||||
next.l_control.scale = Vec3::one();
|
||||
|
@ -2,7 +2,10 @@ use super::{
|
||||
super::{vek::*, Animation},
|
||||
CharacterSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::comp::item::{Hands, ToolKind};
|
||||
use common::{
|
||||
comp::item::{Hands, ToolKind},
|
||||
states::utils::StageSection,
|
||||
};
|
||||
use std::f32::consts::PI;
|
||||
|
||||
pub struct Input {
|
||||
@ -11,7 +14,12 @@ pub struct Input {
|
||||
pub struct SpinAnimation;
|
||||
|
||||
impl Animation for SpinAnimation {
|
||||
type Dependency = (Option<ToolKind>, Option<ToolKind>, f64);
|
||||
type Dependency = (
|
||||
Option<ToolKind>,
|
||||
Option<ToolKind>,
|
||||
f64,
|
||||
Option<StageSection>,
|
||||
);
|
||||
type Skeleton = CharacterSkeleton;
|
||||
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
@ -20,7 +28,7 @@ impl Animation for SpinAnimation {
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_spin")]
|
||||
fn update_skeleton_inner(
|
||||
skeleton: &Self::Skeleton,
|
||||
(active_tool_kind, second_tool_kind, _global_time): Self::Dependency,
|
||||
(active_tool_kind, second_tool_kind, _global_time, stage_section): Self::Dependency,
|
||||
anim_time: f64,
|
||||
rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
@ -40,9 +48,86 @@ impl Animation for SpinAnimation {
|
||||
let spin = (anim_time as f32 * 2.8 * lab as f32).sin();
|
||||
let spinhalf = (anim_time as f32 * 1.4 * lab as f32).sin();
|
||||
|
||||
if let Some(
|
||||
ToolKind::Axe(_) | ToolKind::Hammer(_) | ToolKind::Sword(_) | ToolKind::Dagger(_),
|
||||
) = active_tool_kind
|
||||
let build = (anim_time as f32 * 8.0).sin();
|
||||
let recover = (anim_time as f32 * 8.0).sin();
|
||||
|
||||
let movement = anim_time as f32 * 1.0;
|
||||
let stab = (anim_time as f32 * 8.0).sin();
|
||||
let rotate = (anim_time as f32 * 1.0).sin();
|
||||
|
||||
next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
|
||||
if let Some(ToolKind::Sword(_)) = active_tool_kind {
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2);
|
||||
next.l_hand.scale = Vec3::one() * 1.04;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -0.5);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(0.0, 0.0, 2.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.1)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
|
||||
if let Some(stage_section) = stage_section {
|
||||
match stage_section {
|
||||
StageSection::Buildup => {
|
||||
//println!("{:.3} build", anim_time);
|
||||
next.control.position =
|
||||
Vec3::new(5.0, 11.0 + build * 0.6, 2.0 + build * 0.6);
|
||||
next.control.orientation = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(-0.57 + movement * 2.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.chest.orientation = Quaternion::rotation_y(movement * -0.1)
|
||||
* Quaternion::rotation_z(-1.07 + movement * -0.6);
|
||||
next.belt.orientation = Quaternion::rotation_x(movement * 0.1);
|
||||
|
||||
next.shorts.orientation = Quaternion::rotation_x(movement * 0.1);
|
||||
|
||||
next.head.orientation = Quaternion::rotation_y(movement * 0.1)
|
||||
* Quaternion::rotation_z(1.07 + movement * 0.4);
|
||||
},
|
||||
StageSection::Swing => {
|
||||
//println!("{:.3} swing", anim_time);
|
||||
next.control.position = Vec3::new(
|
||||
7.0 + movement * -8.0,
|
||||
11.0 + stab * 3.0,
|
||||
2.0 + stab * 3.5 + movement * 3.0,
|
||||
);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(-1.57 + movement * -0.6 + stab * -0.25)
|
||||
* Quaternion::rotation_y(2.8 + movement * -2.0)
|
||||
* Quaternion::rotation_z(1.0 + movement * 1.0);
|
||||
next.head.orientation = Quaternion::rotation_z(-stab * 0.8);
|
||||
next.chest.orientation = Quaternion::rotation_x(stab * 0.15)
|
||||
* Quaternion::rotation_y(movement * 0.3)
|
||||
* Quaternion::rotation_z(movement * 1.5);
|
||||
next.belt.orientation = Quaternion::rotation_z(rotate * 0.5);
|
||||
next.shorts.orientation = Quaternion::rotation_z(rotate * 1.5);
|
||||
next.torso.orientation = Quaternion::rotation_z(rotate * 7.2);
|
||||
},
|
||||
StageSection::Recover => {
|
||||
//println!("{:.3} recover", anim_time);
|
||||
next.control.position = Vec3::new(
|
||||
-8.0,
|
||||
11.0 - recover * 0.8 + movement * -10.0,
|
||||
6.0 - recover * 0.4 + movement * -4.0,
|
||||
);
|
||||
next.control.orientation = Quaternion::rotation_x(-1.57)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(1.0);
|
||||
next.chest.orientation = Quaternion::rotation_y(movement * -0.1)
|
||||
* Quaternion::rotation_z(movement * 0.4);
|
||||
next.head.orientation = Quaternion::rotation_y(movement * 0.1)
|
||||
* Quaternion::rotation_z(movement * -0.1);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
// println!("{:?}", stage_progress),
|
||||
|
||||
if let Some(ToolKind::Axe(_) | ToolKind::Hammer(_) | ToolKind::Dagger(_)) = active_tool_kind
|
||||
{
|
||||
//INTENTION: SWORD
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5);
|
||||
@ -88,46 +173,47 @@ impl Animation for SpinAnimation {
|
||||
* Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
|
||||
next.l_foot.position =
|
||||
Vec3::new(-skeleton_attr.foot.0, foot * 1.0, skeleton_attr.foot.2);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(foot * -1.2);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position =
|
||||
Vec3::new(skeleton_attr.foot.0, foot * -1.0, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(foot * 1.2);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.l_shoulder.position = Vec3::new(-5.0, 0.0, 4.7);
|
||||
next.l_shoulder.orientation = Quaternion::rotation_x(0.0);
|
||||
next.l_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.r_shoulder.position = Vec3::new(5.0, 0.0, 4.7);
|
||||
next.r_shoulder.orientation = Quaternion::rotation_x(0.0);
|
||||
next.r_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.glider.position = Vec3::new(0.0, 5.0, 0.0);
|
||||
next.glider.orientation = Quaternion::rotation_y(0.0);
|
||||
next.glider.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.lantern.position = Vec3::new(
|
||||
skeleton_attr.lantern.0,
|
||||
skeleton_attr.lantern.1,
|
||||
skeleton_attr.lantern.2,
|
||||
);
|
||||
next.lantern.orientation =
|
||||
Quaternion::rotation_x(spin * -0.7 + 0.4) * Quaternion::rotation_y(spin * 0.4);
|
||||
next.lantern.scale = Vec3::one() * 0.65;
|
||||
next.hold.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.l_control.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.l_control.orientation = Quaternion::rotation_x(0.0);
|
||||
next.l_control.scale = Vec3::one();
|
||||
|
||||
next.r_control.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.r_control.orientation = Quaternion::rotation_x(0.0);
|
||||
next.r_control.scale = Vec3::one();
|
||||
}
|
||||
|
||||
next.l_foot.position = Vec3::new(-skeleton_attr.foot.0, foot * 1.0, skeleton_attr.foot.2);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(foot * -1.2);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position = Vec3::new(skeleton_attr.foot.0, foot * -1.0, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(foot * 1.2);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.l_shoulder.position = Vec3::new(-5.0, 0.0, 4.7);
|
||||
next.l_shoulder.orientation = Quaternion::rotation_x(0.0);
|
||||
next.l_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.r_shoulder.position = Vec3::new(5.0, 0.0, 4.7);
|
||||
next.r_shoulder.orientation = Quaternion::rotation_x(0.0);
|
||||
next.r_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.glider.position = Vec3::new(0.0, 5.0, 0.0);
|
||||
next.glider.orientation = Quaternion::rotation_y(0.0);
|
||||
next.glider.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.lantern.position = Vec3::new(
|
||||
skeleton_attr.lantern.0,
|
||||
skeleton_attr.lantern.1,
|
||||
skeleton_attr.lantern.2,
|
||||
);
|
||||
next.lantern.orientation =
|
||||
Quaternion::rotation_x(spin * -0.7 + 0.4) * Quaternion::rotation_y(spin * 0.4);
|
||||
next.lantern.scale = Vec3::one() * 0.65;
|
||||
next.hold.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.l_control.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.l_control.orientation = Quaternion::rotation_x(0.0);
|
||||
next.l_control.scale = Vec3::one();
|
||||
|
||||
next.r_control.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.r_control.orientation = Quaternion::rotation_x(0.0);
|
||||
next.r_control.scale = Vec3::one();
|
||||
|
||||
next.second.scale = match (
|
||||
active_tool_kind.map(|tk| tk.hands()),
|
||||
second_tool_kind.map(|tk| tk.hands()),
|
||||
|
@ -2,13 +2,22 @@ use super::{
|
||||
super::{vek::*, Animation},
|
||||
CharacterSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::comp::item::{Hands, ToolKind};
|
||||
use common::{
|
||||
comp::item::{Hands, ToolKind},
|
||||
states::utils::StageSection,
|
||||
};
|
||||
use std::f32::consts::PI;
|
||||
|
||||
pub struct SpinMeleeAnimation;
|
||||
|
||||
impl Animation for SpinMeleeAnimation {
|
||||
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")]
|
||||
@ -18,7 +27,7 @@ impl Animation for SpinMeleeAnimation {
|
||||
#[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,
|
||||
@ -44,109 +53,205 @@ impl Animation for SpinMeleeAnimation {
|
||||
} else {
|
||||
lab as f32 * anim_time as f32 * 0.9
|
||||
};
|
||||
let movement = anim_time as f32 * 1.0;
|
||||
|
||||
//feet
|
||||
let slowersmooth = (anim_time as f32 * lab as f32 * 4.0).sin();
|
||||
let quick = (anim_time as f32 * lab as f32 * 8.0).sin();
|
||||
|
||||
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(PI);
|
||||
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);
|
||||
match active_tool_kind {
|
||||
Some(ToolKind::Sword(_)) => {
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5);
|
||||
next.l_hand.orientation =
|
||||
Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2);
|
||||
next.l_hand.scale = Vec3::one() * 1.04;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -0.5);
|
||||
next.r_hand.orientation =
|
||||
Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(0.0, 0.0, 2.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.1)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.head.position =
|
||||
Vec3::new(0.0, skeleton_attr.head.0 + 0.0, skeleton_attr.head.1);
|
||||
|
||||
next.control.position = Vec3::new(0.0, 16.0, 3.0);
|
||||
next.control.orientation = Quaternion::rotation_x(-1.4)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(1.4);
|
||||
next.control.scale = Vec3::one();
|
||||
if let Some(stage_section) = stage_section {
|
||||
match stage_section {
|
||||
StageSection::Buildup => {
|
||||
next.control.position =
|
||||
Vec3::new(-7.0, 7.0 + movement * -8.0, 2.0 + movement * -6.0);
|
||||
next.control.orientation = Quaternion::rotation_x(movement * -0.5)
|
||||
* Quaternion::rotation_y(movement * 0.3)
|
||||
* Quaternion::rotation_z(movement * -1.5);
|
||||
next.chest.position = Vec3::new(
|
||||
0.0,
|
||||
skeleton_attr.chest.0 + movement * -1.0,
|
||||
skeleton_attr.chest.1 + movement * -2.5,
|
||||
);
|
||||
next.chest.orientation = Quaternion::rotation_x(movement * -1.1)
|
||||
* Quaternion::rotation_z(movement * -0.35);
|
||||
next.belt.orientation = Quaternion::rotation_z(movement * 0.35);
|
||||
next.shorts.orientation = Quaternion::rotation_z(movement * 0.5);
|
||||
next.head.position = Vec3::new(
|
||||
0.0,
|
||||
skeleton_attr.head.0 - 2.0 + movement * -6.0,
|
||||
skeleton_attr.head.1 + movement * -4.0,
|
||||
);
|
||||
next.head.orientation = Quaternion::rotation_x(movement * 0.9)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(movement * 0.05);
|
||||
|
||||
next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
next.head.orientation = Quaternion::rotation_z(0.0)
|
||||
* Quaternion::rotation_x(-0.15)
|
||||
* Quaternion::rotation_y(0.08);
|
||||
next.chest.position = Vec3::new(
|
||||
0.0,
|
||||
skeleton_attr.chest.0 - 3.0,
|
||||
skeleton_attr.chest.1 - 2.0,
|
||||
);
|
||||
next.chest.orientation = Quaternion::rotation_z(0.0)
|
||||
* Quaternion::rotation_x(-0.1)
|
||||
* Quaternion::rotation_y(0.3);
|
||||
next.chest.scale = Vec3::one();
|
||||
next.l_foot.position = Vec3::new(
|
||||
-skeleton_attr.foot.0,
|
||||
skeleton_attr.foot.1 + movement * 4.0,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(movement * 0.2);
|
||||
next.r_foot.position = Vec3::new(
|
||||
skeleton_attr.foot.0,
|
||||
skeleton_attr.foot.1 + movement * -12.0,
|
||||
skeleton_attr.foot.2 + movement * 1.0 + quick * 1.0,
|
||||
);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(movement * -1.0)
|
||||
* Quaternion::rotation_z(movement * -0.8);
|
||||
},
|
||||
StageSection::Swing => {
|
||||
next.head.position =
|
||||
Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
|
||||
next.belt.position = Vec3::new(0.0, 1.0, -1.0);
|
||||
next.belt.orientation = Quaternion::rotation_z(0.0)
|
||||
* Quaternion::rotation_x(0.4)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
next.belt.scale = Vec3::one() * 0.98;
|
||||
next.shorts.position = Vec3::new(0.0, 3.0, -2.5);
|
||||
next.shorts.orientation = Quaternion::rotation_z(0.0)
|
||||
* Quaternion::rotation_x(0.7)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
next.shorts.scale = Vec3::one();
|
||||
next.torso.position = Vec3::new(
|
||||
-xshift * (anim_time as f32).min(0.6),
|
||||
-yshift * (anim_time as f32).min(0.6),
|
||||
0.0,
|
||||
) * skeleton_attr.scaler;
|
||||
next.torso.orientation = Quaternion::rotation_z(spin * -16.0)
|
||||
* Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
next.control.position = Vec3::new(-7.0, 7.0, 2.0);
|
||||
next.control.orientation = Quaternion::rotation_x(-PI / 2.0)
|
||||
* Quaternion::rotation_z(-PI / 2.0);
|
||||
next.torso.orientation = Quaternion::rotation_z(movement * PI * 2.0);
|
||||
|
||||
next.chest.position =
|
||||
Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1);
|
||||
next.chest.orientation = Quaternion::rotation_y(0.3);
|
||||
next.head.position =
|
||||
Vec3::new(0.0, skeleton_attr.head.0 - 2.0, skeleton_attr.head.1);
|
||||
next.head.orientation = Quaternion::rotation_x(-0.15);
|
||||
next.belt.orientation = Quaternion::rotation_x(0.1);
|
||||
next.shorts.orientation = Quaternion::rotation_x(0.2);
|
||||
},
|
||||
StageSection::Recover => {
|
||||
next.head.position =
|
||||
Vec3::new(0.0, skeleton_attr.head.0 - 2.0, skeleton_attr.head.1);
|
||||
next.control.position = Vec3::new(-7.0, 7.0, 2.0);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(-PI / 2.0 + movement * PI / 2.0)
|
||||
* Quaternion::rotation_z(-PI / 2.0 + movement * PI / 2.0);
|
||||
next.head.orientation = Quaternion::rotation_x(-0.15 + movement * 0.15);
|
||||
next.chest.orientation = Quaternion::rotation_y(0.3 + movement * -0.3)
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(ToolKind::Axe(_)) => {
|
||||
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(PI);
|
||||
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(0.0, 16.0, 3.0);
|
||||
next.control.orientation = Quaternion::rotation_x(-1.4)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(1.4);
|
||||
next.control.scale = Vec3::one();
|
||||
|
||||
next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1);
|
||||
next.head.orientation = Quaternion::rotation_z(0.0)
|
||||
* Quaternion::rotation_x(-0.15)
|
||||
* Quaternion::rotation_y(0.08);
|
||||
next.chest.position = Vec3::new(
|
||||
0.0,
|
||||
skeleton_attr.chest.0 - 3.0,
|
||||
skeleton_attr.chest.1 - 2.0,
|
||||
);
|
||||
next.chest.orientation = Quaternion::rotation_z(0.0)
|
||||
* Quaternion::rotation_x(-0.1)
|
||||
* Quaternion::rotation_y(0.3);
|
||||
next.chest.scale = Vec3::one();
|
||||
|
||||
next.belt.position = Vec3::new(0.0, 1.0, -1.0);
|
||||
next.belt.orientation = Quaternion::rotation_z(0.0)
|
||||
* Quaternion::rotation_x(0.4)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
next.belt.scale = Vec3::one() * 0.98;
|
||||
next.shorts.position = Vec3::new(0.0, 3.0, -2.5);
|
||||
next.shorts.orientation = Quaternion::rotation_z(0.0)
|
||||
* Quaternion::rotation_x(0.7)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
next.shorts.scale = Vec3::one();
|
||||
next.torso.position = Vec3::new(
|
||||
-xshift * (anim_time as f32).min(0.6),
|
||||
-yshift * (anim_time as f32).min(0.6),
|
||||
0.0,
|
||||
) * skeleton_attr.scaler;
|
||||
next.torso.orientation = Quaternion::rotation_z(spin * -16.0)
|
||||
* Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
if velocity.z.abs() > 0.1 {
|
||||
next.l_foot.position =
|
||||
Vec3::new(-skeleton_attr.foot.0, 8.0, skeleton_attr.foot.2 + 2.0);
|
||||
next.l_foot.orientation =
|
||||
Quaternion::rotation_x(1.0) * Quaternion::rotation_z(0.0);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position =
|
||||
Vec3::new(skeleton_attr.foot.0, 8.0, skeleton_attr.foot.2 + 2.0);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(1.0);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
} else if speed < 0.5 {
|
||||
next.l_foot.position = Vec3::new(
|
||||
-skeleton_attr.foot.0,
|
||||
2.0 + quick * -6.0,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(0.5 + slowersmooth * 0.2)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position =
|
||||
Vec3::new(skeleton_attr.foot.0, 4.0, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(0.5 - slowersmooth * 0.2)
|
||||
* Quaternion::rotation_y(-0.4);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
} else {
|
||||
next.l_foot.position = Vec3::new(
|
||||
-skeleton_attr.foot.0,
|
||||
2.0 + quick * -6.0,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(0.5 + slowersmooth * 0.2)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position = Vec3::new(
|
||||
skeleton_attr.foot.0,
|
||||
2.0 + quick * 6.0,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(0.5 - slowersmooth * 0.2)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
};
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
if velocity.z.abs() > 0.1 {
|
||||
next.l_foot.position =
|
||||
Vec3::new(-skeleton_attr.foot.0, 8.0, skeleton_attr.foot.2 + 2.0);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(1.0) * Quaternion::rotation_z(0.0);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position = Vec3::new(skeleton_attr.foot.0, 8.0, skeleton_attr.foot.2 + 2.0);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(1.0);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
} else if speed < 0.5 {
|
||||
next.l_foot.position = Vec3::new(
|
||||
-skeleton_attr.foot.0,
|
||||
2.0 + quick * -6.0,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.l_foot.orientation =
|
||||
Quaternion::rotation_x(0.5 + slowersmooth * 0.2) * Quaternion::rotation_z(0.0);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position = Vec3::new(skeleton_attr.foot.0, 4.0, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation =
|
||||
Quaternion::rotation_x(0.5 - slowersmooth * 0.2) * Quaternion::rotation_y(-0.4);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
} else {
|
||||
next.l_foot.position = Vec3::new(
|
||||
-skeleton_attr.foot.0,
|
||||
2.0 + quick * -6.0,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.l_foot.orientation =
|
||||
Quaternion::rotation_x(0.5 + slowersmooth * 0.2) * Quaternion::rotation_z(0.0);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position = Vec3::new(
|
||||
skeleton_attr.foot.0,
|
||||
2.0 + quick * 6.0,
|
||||
skeleton_attr.foot.2,
|
||||
);
|
||||
next.r_foot.orientation =
|
||||
Quaternion::rotation_x(0.5 - slowersmooth * 0.2) * Quaternion::rotation_z(0.0);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
};
|
||||
next.lantern.position = Vec3::new(
|
||||
skeleton_attr.lantern.0,
|
||||
skeleton_attr.lantern.1,
|
||||
|
@ -41,7 +41,7 @@ impl Animation for StandAnimation {
|
||||
);
|
||||
next.head.position = Vec3::new(
|
||||
0.0,
|
||||
-3.0 + skeleton_attr.head.0,
|
||||
-2.0 + skeleton_attr.head.0,
|
||||
skeleton_attr.head.1 + slow * 0.3 + breathe * -0.05,
|
||||
);
|
||||
next.head.orientation = Quaternion::rotation_z(head_look.x)
|
||||
@ -174,7 +174,7 @@ impl Animation for StandAnimation {
|
||||
next.lantern.orientation = Quaternion::rotation_x(0.1) * Quaternion::rotation_y(0.1);
|
||||
next.lantern.scale = Vec3::one() * 0.65;
|
||||
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.) * skeleton_attr.scaler;
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.0) * skeleton_attr.scaler;
|
||||
next.torso.orientation = Quaternion::rotation_x(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
|
||||
|
@ -111,18 +111,18 @@ impl Animation for WieldAnimation {
|
||||
match active_tool_kind {
|
||||
//TODO: Inventory
|
||||
Some(ToolKind::Sword(_)) => {
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5);
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5);
|
||||
next.l_hand.orientation =
|
||||
Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2);
|
||||
next.l_hand.scale = Vec3::one() * 1.04;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -5.5);
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -0.5);
|
||||
next.r_hand.orientation =
|
||||
Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(0.0, 0.0, -3.0);
|
||||
next.main.orientation = Quaternion::rotation_x(-0.1);
|
||||
|
||||
next.control.position = Vec3::new(-7.0, 6.0, 6.0);
|
||||
next.control.position = Vec3::new(-7.0, 7.0, 2.0);
|
||||
next.control.orientation = Quaternion::rotation_x(u_slow * 0.15)
|
||||
* Quaternion::rotation_z(u_slowalt * 0.08);
|
||||
next.control.scale = Vec3::one();
|
||||
|
@ -113,15 +113,34 @@ fn matches_ability_stage() {
|
||||
});
|
||||
|
||||
let result = CombatEventMapper::map_event(
|
||||
&CharacterState::TripleStrike(states::triple_strike::Data {
|
||||
base_damage: 10,
|
||||
stage: states::triple_strike::Stage::First,
|
||||
stage_time_active: Duration::default(),
|
||||
stage_exhausted: false,
|
||||
initialized: true,
|
||||
transition_style: states::triple_strike::TransitionStyle::Hold(
|
||||
states::triple_strike::HoldingState::Released,
|
||||
),
|
||||
&CharacterState::ComboMelee(states::combo_melee::Data {
|
||||
static_data: states::combo_melee::StaticData {
|
||||
num_stages: 1,
|
||||
stage_data: vec![states::combo_melee::Stage {
|
||||
stage: 1,
|
||||
base_damage: 100,
|
||||
max_damage: 120,
|
||||
damage_increase: 10,
|
||||
knockback: 10.0,
|
||||
range: 4.0,
|
||||
angle: 30.0,
|
||||
base_buildup_duration: Duration::from_millis(500),
|
||||
base_swing_duration: Duration::from_millis(200),
|
||||
base_recover_duration: Duration::from_millis(400),
|
||||
forward_movement: 0.5,
|
||||
}],
|
||||
initial_energy_gain: 0,
|
||||
max_energy_gain: 100,
|
||||
energy_increase: 20,
|
||||
speed_increase: 0.05,
|
||||
max_speed_increase: 1.8,
|
||||
is_interruptible: true,
|
||||
},
|
||||
stage: 1,
|
||||
combo: 0,
|
||||
timer: Duration::default(),
|
||||
stage_section: states::utils::StageSection::Swing,
|
||||
next_stage: false,
|
||||
}),
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
@ -134,7 +153,7 @@ fn matches_ability_stage() {
|
||||
assert_eq!(
|
||||
result,
|
||||
SfxEvent::Attack(
|
||||
CharacterAbilityType::TripleStrike(states::triple_strike::Stage::First),
|
||||
CharacterAbilityType::ComboMelee(states::utils::StageSection::Swing, 1),
|
||||
ToolCategory::Sword
|
||||
)
|
||||
);
|
||||
@ -154,15 +173,34 @@ fn ignores_different_ability_stage() {
|
||||
});
|
||||
|
||||
let result = CombatEventMapper::map_event(
|
||||
&CharacterState::TripleStrike(states::triple_strike::Data {
|
||||
base_damage: 10,
|
||||
stage: states::triple_strike::Stage::Second,
|
||||
stage_time_active: Duration::default(),
|
||||
stage_exhausted: false,
|
||||
initialized: true,
|
||||
transition_style: states::triple_strike::TransitionStyle::Hold(
|
||||
states::triple_strike::HoldingState::Released,
|
||||
),
|
||||
&CharacterState::ComboMelee(states::combo_melee::Data {
|
||||
static_data: states::combo_melee::StaticData {
|
||||
num_stages: 1,
|
||||
stage_data: vec![states::combo_melee::Stage {
|
||||
stage: 1,
|
||||
base_damage: 100,
|
||||
max_damage: 120,
|
||||
damage_increase: 10,
|
||||
knockback: 10.0,
|
||||
range: 4.0,
|
||||
angle: 30.0,
|
||||
base_buildup_duration: Duration::from_millis(500),
|
||||
base_swing_duration: Duration::from_millis(200),
|
||||
base_recover_duration: Duration::from_millis(400),
|
||||
forward_movement: 0.5,
|
||||
}],
|
||||
initial_energy_gain: 0,
|
||||
max_energy_gain: 100,
|
||||
energy_increase: 20,
|
||||
speed_increase: 0.05,
|
||||
max_speed_increase: 1.8,
|
||||
is_interruptible: true,
|
||||
},
|
||||
stage: 1,
|
||||
combo: 0,
|
||||
timer: Duration::default(),
|
||||
stage_section: states::utils::StageSection::Swing,
|
||||
next_stage: false,
|
||||
}),
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
@ -175,7 +213,7 @@ fn ignores_different_ability_stage() {
|
||||
assert_ne!(
|
||||
result,
|
||||
SfxEvent::Attack(
|
||||
CharacterAbilityType::TripleStrike(states::triple_strike::Stage::First),
|
||||
CharacterAbilityType::ComboMelee(states::utils::StageSection::Swing, 2),
|
||||
ToolCategory::Sword
|
||||
)
|
||||
);
|
||||
|
@ -72,10 +72,9 @@
|
||||
//! threshold: 1.2,
|
||||
//! ),
|
||||
//! // A multi-stage attack ability which depends on the weapon
|
||||
//! Attack(TripleStrike(First), Sword): (
|
||||
//! Attack(ComboMelee(Swing, 1), Sword): (
|
||||
//! files: [
|
||||
//! "voxygen.audio.sfx.weapon.sword_03",
|
||||
//! "voxygen.audio.sfx.weapon.sword_04",
|
||||
//! "voxygen.audio.sfx.abilities.swing_sword",
|
||||
//! ],
|
||||
//! threshold: 0.5,
|
||||
//! ),
|
||||
|
@ -82,7 +82,7 @@ impl State {
|
||||
} else if let ToolKind::Debug(kind) = &kind.kind {
|
||||
kind == "Boost"
|
||||
} else {
|
||||
false
|
||||
matches!(&kind.kind, ToolKind::Sword(_))
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
@ -267,6 +267,7 @@ image_ids! {
|
||||
fire_spell_1: "voxygen.element.icons.fire_spell_0",
|
||||
snake_arrow_0: "voxygen.element.icons.snake",
|
||||
heal_0: "voxygen.element.icons.heal_0",
|
||||
sword_whirlwind: "voxygen.element.icons.sword_whirlwind",
|
||||
|
||||
// Buttons
|
||||
button: "voxygen.element.buttons.button",
|
||||
|
@ -803,6 +803,10 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
"\nWhirls a big fireball into the air. \nExplodes the ground \
|
||||
and does\na big amount of damage",
|
||||
)),
|
||||
ToolKind::Sword(_) => Some((
|
||||
"Whirlwind",
|
||||
"\nMove forward while spinning with \n your sword.",
|
||||
)),
|
||||
ToolKind::Debug(kind) => match kind.as_ref() {
|
||||
"Boost" => Some((
|
||||
"Possessing Arrow",
|
||||
|
@ -84,6 +84,7 @@ pub enum HotbarImage {
|
||||
Item(ItemKey),
|
||||
Fireball,
|
||||
SnakeArrow,
|
||||
SwordWhirlwind,
|
||||
}
|
||||
|
||||
type HotbarSource<'a> = (&'a hotbar::State, &'a Inventory, &'a Loadout, &'a Energy);
|
||||
@ -113,6 +114,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
|
||||
"Boost" => Some(HotbarImage::SnakeArrow),
|
||||
_ => None,
|
||||
},
|
||||
ToolKind::Sword(_) => Some(HotbarImage::SwordWhirlwind),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
@ -143,6 +145,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
|
||||
HotbarImage::Item(key) => item_imgs.img_id_or_not_found_img(key.clone()),
|
||||
HotbarImage::SnakeArrow => imgs.snake_arrow_0,
|
||||
HotbarImage::Fireball => imgs.fire_spell_1,
|
||||
HotbarImage::SwordWhirlwind => imgs.sword_whirlwind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,12 +25,13 @@ use anim::{
|
||||
};
|
||||
use common::{
|
||||
comp::{
|
||||
item::ItemKind, Body, CharacterState, Item, Last, LightAnimation, LightEmitter, Loadout,
|
||||
Ori, PhysicsState, Pos, Scale, Stats, Vel,
|
||||
item::{ItemKind, ToolKind},
|
||||
Body, CharacterState, Item, Last, LightAnimation, LightEmitter, Loadout, Ori, PhysicsState,
|
||||
Pos, Scale, Stats, Vel,
|
||||
},
|
||||
span,
|
||||
state::{DeltaTime, State},
|
||||
states::triple_strike,
|
||||
states::utils::StageSection,
|
||||
terrain::TerrainChunk,
|
||||
vol::RectRasterableVol,
|
||||
};
|
||||
@ -809,7 +810,13 @@ impl FigureMgr {
|
||||
CharacterState::BasicMelee(_) => {
|
||||
anim::character::AlphaAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, second_tool_kind, vel.0.magnitude(), time),
|
||||
(
|
||||
active_tool_kind,
|
||||
second_tool_kind,
|
||||
vel.0.magnitude(),
|
||||
time,
|
||||
None,
|
||||
),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
@ -879,17 +886,43 @@ impl FigureMgr {
|
||||
CharacterState::Boost(_) => {
|
||||
anim::character::AlphaAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, second_tool_kind, vel.0.magnitude(), time),
|
||||
(
|
||||
active_tool_kind,
|
||||
second_tool_kind,
|
||||
vel.0.magnitude(),
|
||||
time,
|
||||
None,
|
||||
),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::DashMelee(_) => {
|
||||
CharacterState::DashMelee(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::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()
|
||||
},
|
||||
};
|
||||
anim::character::DashAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, second_tool_kind, time),
|
||||
state.state_time,
|
||||
(
|
||||
active_tool_kind,
|
||||
second_tool_kind,
|
||||
time,
|
||||
Some(s.stage_section),
|
||||
),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
@ -903,43 +936,106 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::SpinMelee(_) => {
|
||||
CharacterState::SpinMelee(s) => {
|
||||
let stage_progress = match active_tool_kind {
|
||||
Some(ToolKind::Sword(_)) => {
|
||||
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::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::SpinMeleeAnimation::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,
|
||||
)
|
||||
},
|
||||
CharacterState::TripleStrike(s) => match s.stage {
|
||||
triple_strike::Stage::First => {
|
||||
anim::character::AlphaAnimation::update_skeleton(
|
||||
CharacterState::ComboMelee(s) => {
|
||||
let stage_index = (s.stage - 1) as usize;
|
||||
let stage_time = s.timer.as_secs_f64();
|
||||
let stage_progress = match s.stage_section {
|
||||
StageSection::Buildup => {
|
||||
stage_time
|
||||
/ s.static_data.stage_data[stage_index]
|
||||
.base_buildup_duration
|
||||
.as_secs_f64()
|
||||
},
|
||||
StageSection::Swing => {
|
||||
stage_time
|
||||
/ s.static_data.stage_data[stage_index]
|
||||
.base_swing_duration
|
||||
.as_secs_f64()
|
||||
},
|
||||
StageSection::Recover => {
|
||||
stage_time
|
||||
/ s.static_data.stage_data[stage_index]
|
||||
.base_recover_duration
|
||||
.as_secs_f64()
|
||||
},
|
||||
_ => 0.0,
|
||||
};
|
||||
match s.stage {
|
||||
1 => anim::character::AlphaAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, second_tool_kind, vel.0.magnitude(), time),
|
||||
state.state_time,
|
||||
(
|
||||
active_tool_kind,
|
||||
second_tool_kind,
|
||||
vel.0.magnitude(),
|
||||
time,
|
||||
Some(s.stage_section),
|
||||
),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
triple_strike::Stage::Second => {
|
||||
anim::character::SpinAnimation::update_skeleton(
|
||||
),
|
||||
2 => anim::character::SpinAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, second_tool_kind, time),
|
||||
state.state_time,
|
||||
(
|
||||
active_tool_kind,
|
||||
second_tool_kind,
|
||||
time,
|
||||
Some(s.stage_section),
|
||||
),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
triple_strike::Stage::Third => {
|
||||
anim::character::BetaAnimation::update_skeleton(
|
||||
),
|
||||
_ => anim::character::BetaAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, second_tool_kind, vel.0.magnitude(), time),
|
||||
state.state_time,
|
||||
(
|
||||
active_tool_kind,
|
||||
second_tool_kind,
|
||||
vel.0.magnitude(),
|
||||
time,
|
||||
Some(s.stage_section),
|
||||
),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
),
|
||||
}
|
||||
},
|
||||
CharacterState::BasicBlock { .. } => {
|
||||
anim::character::BlockIdleAnimation::update_skeleton(
|
||||
|
Loading…
Reference in New Issue
Block a user