From 1d8e2868f167014819f9509defbbbcc94b50aeaa Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 16 Apr 2021 00:09:15 -0400 Subject: [PATCH 01/19] Charge attack for minotaur functional. --- .../common/abilities/ability_set_manifest.ron | 8 ++++++++ .../abilities/custom/minotaur/charge.ron | 19 +++++++++++++++++++ .../abilities/custom/minotaur/cleave.ron | 19 +++++++++++++++++++ .../custom/minotaur/cripplingstrike.ron | 19 +++++++++++++++++++ .../abilities/custom/minotaur/frenzy.ron | 19 +++++++++++++++++++ .../items/npc_weapons/axe/minotaur_axe.ron | 10 +++++----- 6 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 assets/common/abilities/custom/minotaur/charge.ron create mode 100644 assets/common/abilities/custom/minotaur/cleave.ron create mode 100644 assets/common/abilities/custom/minotaur/cripplingstrike.ron create mode 100644 assets/common/abilities/custom/minotaur/frenzy.ron diff --git a/assets/common/abilities/ability_set_manifest.ron b/assets/common/abilities/ability_set_manifest.ron index 18f67e45e6..1fc621ade6 100644 --- a/assets/common/abilities/ability_set_manifest.ron +++ b/assets/common/abilities/ability_set_manifest.ron @@ -207,6 +207,14 @@ (None, "common.abilities.custom.mindflayer.summonminions"), ], ), + Custom("Minotaur"): ( + primary: "common.abilities.custom.minotaur.charge", + secondary: "common.abilities.custom.minotaur.cripplingstrike", + abilities: [ + (None, "common.abilities.custom.minotaur.cleave"), + (None, "common.abilities.custom.minotaur.frenzy"), + ], + ), Custom("Bird Large Breathe"): ( primary: "common.abilities.custom.birdlargebreathe.firebomb", secondary: "common.abilities.custom.birdlargebreathe.triplestrike", diff --git a/assets/common/abilities/custom/minotaur/charge.ron b/assets/common/abilities/custom/minotaur/charge.ron new file mode 100644 index 0000000000..6563de650a --- /dev/null +++ b/assets/common/abilities/custom/minotaur/charge.ron @@ -0,0 +1,19 @@ +DashMelee( + energy_cost: 0, + base_damage: 500, + scaled_damage: 2000, + base_poise_damage: 25, + scaled_poise_damage: 100, + base_knockback: 10.0, + scaled_knockback: 30.0, + range: 7.5, + angle: 90.0, + energy_drain: 0, + forward_speed: 5.0, + buildup_duration: 0.4, + charge_duration: 4.0, + swing_duration: 0.1, + recover_duration: 0.5, + infinite_charge: false, + is_interruptible: false, +) \ No newline at end of file diff --git a/assets/common/abilities/custom/minotaur/cleave.ron b/assets/common/abilities/custom/minotaur/cleave.ron new file mode 100644 index 0000000000..6563de650a --- /dev/null +++ b/assets/common/abilities/custom/minotaur/cleave.ron @@ -0,0 +1,19 @@ +DashMelee( + energy_cost: 0, + base_damage: 500, + scaled_damage: 2000, + base_poise_damage: 25, + scaled_poise_damage: 100, + base_knockback: 10.0, + scaled_knockback: 30.0, + range: 7.5, + angle: 90.0, + energy_drain: 0, + forward_speed: 5.0, + buildup_duration: 0.4, + charge_duration: 4.0, + swing_duration: 0.1, + recover_duration: 0.5, + infinite_charge: false, + is_interruptible: false, +) \ No newline at end of file diff --git a/assets/common/abilities/custom/minotaur/cripplingstrike.ron b/assets/common/abilities/custom/minotaur/cripplingstrike.ron new file mode 100644 index 0000000000..6563de650a --- /dev/null +++ b/assets/common/abilities/custom/minotaur/cripplingstrike.ron @@ -0,0 +1,19 @@ +DashMelee( + energy_cost: 0, + base_damage: 500, + scaled_damage: 2000, + base_poise_damage: 25, + scaled_poise_damage: 100, + base_knockback: 10.0, + scaled_knockback: 30.0, + range: 7.5, + angle: 90.0, + energy_drain: 0, + forward_speed: 5.0, + buildup_duration: 0.4, + charge_duration: 4.0, + swing_duration: 0.1, + recover_duration: 0.5, + infinite_charge: false, + is_interruptible: false, +) \ No newline at end of file diff --git a/assets/common/abilities/custom/minotaur/frenzy.ron b/assets/common/abilities/custom/minotaur/frenzy.ron new file mode 100644 index 0000000000..6563de650a --- /dev/null +++ b/assets/common/abilities/custom/minotaur/frenzy.ron @@ -0,0 +1,19 @@ +DashMelee( + energy_cost: 0, + base_damage: 500, + scaled_damage: 2000, + base_poise_damage: 25, + scaled_poise_damage: 100, + base_knockback: 10.0, + scaled_knockback: 30.0, + range: 7.5, + angle: 90.0, + energy_drain: 0, + forward_speed: 5.0, + buildup_duration: 0.4, + charge_duration: 4.0, + swing_duration: 0.1, + recover_duration: 0.5, + infinite_charge: false, + is_interruptible: false, +) \ No newline at end of file diff --git a/assets/common/items/npc_weapons/axe/minotaur_axe.ron b/assets/common/items/npc_weapons/axe/minotaur_axe.ron index d1f47d9cdf..db469f4d84 100644 --- a/assets/common/items/npc_weapons/axe/minotaur_axe.ron +++ b/assets/common/items/npc_weapons/axe/minotaur_axe.ron @@ -6,14 +6,14 @@ ItemDef( hands: Two, stats: Direct(( equip_time_secs: 0.5, - power: 1.8, + power: 1.0, poise_strength: 1.0, speed: 1.0, - crit_chance: 0.048611112, - crit_mult: 1.6530613, + crit_chance: 0.1, + crit_mult: 1.5, )), )), - quality: Low, + quality: Legendary, tags: [], - ability_spec: Some(Custom("Axe Simple")), + ability_spec: Some(Custom("Minotaur")), ) \ No newline at end of file From 3e5d9932e9169738db9c4683aefbe4748c12bf48 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 16 Apr 2021 11:56:49 -0400 Subject: [PATCH 02/19] Miscellaneous balancing --- assets/common/abilities/custom/mindflayer/cursedflames.ron | 2 +- .../common/abilities/custom/mindflayer/necroticvortex.ron | 2 +- assets/common/abilities/custom/minotaur/cripplingstrike.ron | 4 ++-- assets/common/items/weapons/hammer/mjolnir.ron | 4 ++-- assets/common/items/weapons/sceptre/caduceus.ron | 4 ++-- assets/common/items/weapons/sceptre/root_evil.ron | 6 +++--- assets/common/items/weapons/sceptre/sceptre_velorite_0.ron | 4 ++-- assets/common/items/weapons/staff/laevateinn.ron | 4 ++-- assets/common/items/weapons/staff/phoenix.ron | 4 ++-- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/assets/common/abilities/custom/mindflayer/cursedflames.ron b/assets/common/abilities/custom/mindflayer/cursedflames.ron index e98d16a0c8..f78afb1eda 100644 --- a/assets/common/abilities/custom/mindflayer/cursedflames.ron +++ b/assets/common/abilities/custom/mindflayer/cursedflames.ron @@ -2,7 +2,7 @@ BasicBeam( buildup_duration: 0.40, recover_duration: 0.50, beam_duration: 1.0, - damage: 350, + damage: 750, tick_rate: 0.9, range: 22.0, max_angle: 15.0, diff --git a/assets/common/abilities/custom/mindflayer/necroticvortex.ron b/assets/common/abilities/custom/mindflayer/necroticvortex.ron index 3b9e308d96..acd6664570 100644 --- a/assets/common/abilities/custom/mindflayer/necroticvortex.ron +++ b/assets/common/abilities/custom/mindflayer/necroticvortex.ron @@ -2,7 +2,7 @@ SpinMelee( buildup_duration: 0.5, swing_duration: 0.2, recover_duration: 0.6, - base_damage: 80.0, + base_damage: 150.0, base_poise_damage: 1.0, knockback: ( strength: 7.0, direction: Towards), range: 16.0, diff --git a/assets/common/abilities/custom/minotaur/cripplingstrike.ron b/assets/common/abilities/custom/minotaur/cripplingstrike.ron index 6563de650a..f57f8d2839 100644 --- a/assets/common/abilities/custom/minotaur/cripplingstrike.ron +++ b/assets/common/abilities/custom/minotaur/cripplingstrike.ron @@ -1,7 +1,7 @@ DashMelee( energy_cost: 0, - base_damage: 500, - scaled_damage: 2000, + base_damage: 300, + scaled_damage: 1200, base_poise_damage: 25, scaled_poise_damage: 100, base_knockback: 10.0, diff --git a/assets/common/items/weapons/hammer/mjolnir.ron b/assets/common/items/weapons/hammer/mjolnir.ron index 831e3a0a99..cd812ba36a 100644 --- a/assets/common/items/weapons/hammer/mjolnir.ron +++ b/assets/common/items/weapons/hammer/mjolnir.ron @@ -6,9 +6,9 @@ ItemDef( hands: Two, stats: Direct(( equip_time_secs: 0.5, - power: 4.0, + power: 2.5, poise_strength: 1.0, - speed: 0.5, + speed: 0.8, crit_chance: 0.078125, crit_mult: 1.3657143, )), diff --git a/assets/common/items/weapons/sceptre/caduceus.ron b/assets/common/items/weapons/sceptre/caduceus.ron index 09bf7152b7..2e0e790e50 100644 --- a/assets/common/items/weapons/sceptre/caduceus.ron +++ b/assets/common/items/weapons/sceptre/caduceus.ron @@ -6,9 +6,9 @@ ItemDef( hands: Two, stats: Direct(( equip_time_secs: 0.4, - power: 2.3, + power: 1.67, poise_strength: 1.5, - speed: 1.0, + speed: 1.2, crit_chance: 0.078125, crit_mult: 1.3657143, )), diff --git a/assets/common/items/weapons/sceptre/root_evil.ron b/assets/common/items/weapons/sceptre/root_evil.ron index d33ba4f461..dd26418355 100644 --- a/assets/common/items/weapons/sceptre/root_evil.ron +++ b/assets/common/items/weapons/sceptre/root_evil.ron @@ -6,9 +6,9 @@ ItemDef( hands: Two, stats: Direct(( equip_time_secs: 0.4, - power: 4.0, - poise_strength: 1.5, - speed: 0.5, + power: 2.5, + poise_strength: 1.0, + speed: 0.8, crit_chance: 0.078125, crit_mult: 1.3657143, )), diff --git a/assets/common/items/weapons/sceptre/sceptre_velorite_0.ron b/assets/common/items/weapons/sceptre/sceptre_velorite_0.ron index 9dfbc9e842..d650b11ada 100644 --- a/assets/common/items/weapons/sceptre/sceptre_velorite_0.ron +++ b/assets/common/items/weapons/sceptre/sceptre_velorite_0.ron @@ -6,9 +6,9 @@ ItemDef( hands: Two, stats: Direct(( equip_time_secs: 0.4, - power: 1.8, + power: 2.0, poise_strength: 1.5, - speed: 1.2, + speed: 1.0, crit_chance: 0.21153846, crit_mult: 1.4502164, )), diff --git a/assets/common/items/weapons/staff/laevateinn.ron b/assets/common/items/weapons/staff/laevateinn.ron index 29c302e35e..9b7fca332b 100644 --- a/assets/common/items/weapons/staff/laevateinn.ron +++ b/assets/common/items/weapons/staff/laevateinn.ron @@ -6,9 +6,9 @@ ItemDef( hands: Two, stats: Direct(( equip_time_secs: 0.6, - power: 1.8, + power: 1.67, poise_strength: 1.0, - speed: 1.6, + speed: 1.2, crit_chance: 0.2002994, crit_mult: 1.3798152, )), diff --git a/assets/common/items/weapons/staff/phoenix.ron b/assets/common/items/weapons/staff/phoenix.ron index efaa30e77d..39acf85d40 100644 --- a/assets/common/items/weapons/staff/phoenix.ron +++ b/assets/common/items/weapons/staff/phoenix.ron @@ -6,9 +6,9 @@ ItemDef( hands: Two, stats: Direct(( equip_time_secs: 0.6, - power: 3.0, + power: 2.5, poise_strength: 1.0, - speed: 0.67, + speed: 0.8, crit_chance: 0.1002994, crit_mult: 1.3798152, )), From c79c929e9f3f40201338fa668391b8d46ff02a74 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 16 Apr 2021 13:44:11 -0400 Subject: [PATCH 03/19] Crippling strike now functional. Crippled debuff added. --- .../common/abilities/ability_set_manifest.ron | 4 +-- .../abilities/custom/beastclaws/basic.ron | 1 + .../custom/minotaur/cripplingstrike.ron | 34 +++++++++---------- .../abilities/custom/quadmedhoof/basic.ron | 1 + assets/common/abilities/dagger/tempbasic.ron | 1 + assets/common/abilities/empty/basic.ron | 1 + assets/common/abilities/farming/basic.ron | 1 + assets/common/abilities/pick/swing.ron | 1 + assets/common/abilities/shield/tempbasic.ron | 1 + common/src/comp/ability.rs | 4 +++ common/src/comp/buff.rs | 20 ++++++++++- common/src/comp/stats.rs | 4 +++ common/src/states/basic_melee.rs | 15 +++++--- common/src/states/dash_melee.rs | 1 - common/src/states/spin_melee.rs | 1 - common/src/states/utils.rs | 7 ++++ common/systems/src/buff.rs | 3 ++ voxygen/src/hud/mod.rs | 4 +++ voxygen/src/hud/util.rs | 6 ++-- 19 files changed, 81 insertions(+), 29 deletions(-) diff --git a/assets/common/abilities/ability_set_manifest.ron b/assets/common/abilities/ability_set_manifest.ron index 1fc621ade6..33150c51e5 100644 --- a/assets/common/abilities/ability_set_manifest.ron +++ b/assets/common/abilities/ability_set_manifest.ron @@ -208,10 +208,10 @@ ], ), Custom("Minotaur"): ( - primary: "common.abilities.custom.minotaur.charge", + primary: "common.abilities.custom.minotaur.cleave", secondary: "common.abilities.custom.minotaur.cripplingstrike", abilities: [ - (None, "common.abilities.custom.minotaur.cleave"), + (None, "common.abilities.custom.minotaur.charge"), (None, "common.abilities.custom.minotaur.frenzy"), ], ), diff --git a/assets/common/abilities/custom/beastclaws/basic.ron b/assets/common/abilities/custom/beastclaws/basic.ron index 6104f35b8b..449aa4b206 100644 --- a/assets/common/abilities/custom/beastclaws/basic.ron +++ b/assets/common/abilities/custom/beastclaws/basic.ron @@ -8,4 +8,5 @@ BasicMelee( base_poise_damage: 40, range: 5.0, max_angle: 120.0, + damage_effect: None, ) diff --git a/assets/common/abilities/custom/minotaur/cripplingstrike.ron b/assets/common/abilities/custom/minotaur/cripplingstrike.ron index f57f8d2839..fbc946b9ed 100644 --- a/assets/common/abilities/custom/minotaur/cripplingstrike.ron +++ b/assets/common/abilities/custom/minotaur/cripplingstrike.ron @@ -1,19 +1,17 @@ -DashMelee( +BasicMelee( energy_cost: 0, - base_damage: 300, - scaled_damage: 1200, - base_poise_damage: 25, - scaled_poise_damage: 100, - base_knockback: 10.0, - scaled_knockback: 30.0, - range: 7.5, - angle: 90.0, - energy_drain: 0, - forward_speed: 5.0, - buildup_duration: 0.4, - charge_duration: 4.0, - swing_duration: 0.1, - recover_duration: 0.5, - infinite_charge: false, - is_interruptible: false, -) \ No newline at end of file + buildup_duration: 0.3, + swing_duration: 0.2, + recover_duration: 0.6, + base_damage: 250.0, + base_poise_damage: 60.0, + knockback: 25.0, + range: 5.0, + max_angle: 90.0, + damage_effect: Some(Buff(( + kind: Crippled, + dur_secs: 15.0, + strength: Value(0.5), + chance: 1.0, + ))), +) diff --git a/assets/common/abilities/custom/quadmedhoof/basic.ron b/assets/common/abilities/custom/quadmedhoof/basic.ron index a451c250e0..73c4e7d739 100644 --- a/assets/common/abilities/custom/quadmedhoof/basic.ron +++ b/assets/common/abilities/custom/quadmedhoof/basic.ron @@ -8,4 +8,5 @@ BasicMelee( knockback: 25.0, range: 1.2, max_angle: 50.0, + damage_effect: None, ) diff --git a/assets/common/abilities/dagger/tempbasic.ron b/assets/common/abilities/dagger/tempbasic.ron index 27bed0eca3..5149caf41c 100644 --- a/assets/common/abilities/dagger/tempbasic.ron +++ b/assets/common/abilities/dagger/tempbasic.ron @@ -8,4 +8,5 @@ BasicMelee( knockback: 0.0, range: 3.5, max_angle: 20.0, + damage_effect: None, ) diff --git a/assets/common/abilities/empty/basic.ron b/assets/common/abilities/empty/basic.ron index e6c7d2f0ff..10d9ae81d8 100644 --- a/assets/common/abilities/empty/basic.ron +++ b/assets/common/abilities/empty/basic.ron @@ -8,4 +8,5 @@ BasicMelee( knockback: 0.0, range: 3.5, max_angle: 15.0, + damage_effect: None, ) diff --git a/assets/common/abilities/farming/basic.ron b/assets/common/abilities/farming/basic.ron index 2d8ff06774..44e52a5711 100644 --- a/assets/common/abilities/farming/basic.ron +++ b/assets/common/abilities/farming/basic.ron @@ -8,4 +8,5 @@ BasicMelee( knockback: 0.0, range: 3.5, max_angle: 20.0, + damage_effect: None, ) diff --git a/assets/common/abilities/pick/swing.ron b/assets/common/abilities/pick/swing.ron index 2d8ff06774..44e52a5711 100644 --- a/assets/common/abilities/pick/swing.ron +++ b/assets/common/abilities/pick/swing.ron @@ -8,4 +8,5 @@ BasicMelee( knockback: 0.0, range: 3.5, max_angle: 20.0, + damage_effect: None, ) diff --git a/assets/common/abilities/shield/tempbasic.ron b/assets/common/abilities/shield/tempbasic.ron index 6998b394b5..5e7e156fe7 100644 --- a/assets/common/abilities/shield/tempbasic.ron +++ b/assets/common/abilities/shield/tempbasic.ron @@ -8,4 +8,5 @@ BasicMelee( knockback: 0.0, range: 3.0, max_angle: 120.0, + damage_effect: None, ) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index e9a1de7c2c..5ec986c363 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -66,6 +66,7 @@ pub enum CharacterAbility { knockback: f32, range: f32, max_angle: f32, + damage_effect: Option, }, BasicRanged { energy_cost: f32, @@ -282,6 +283,7 @@ impl Default for CharacterAbility { knockback: 0.0, range: 3.5, max_angle: 15.0, + damage_effect: None, } } } @@ -1164,6 +1166,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState { knockback, range, max_angle, + damage_effect, energy_cost: _, } => CharacterState::BasicMelee(basic_melee::Data { static_data: basic_melee::StaticData { @@ -1175,6 +1178,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState { knockback: *knockback, range: *range, max_angle: *max_angle, + damage_effect: *damage_effect, ability_info, }, timer: Duration::default(), diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index 790313db6c..f93c419855 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -36,6 +36,8 @@ pub enum BuffKind { Invulnerability, /// Reduces incoming damage ProtectingWard, + /// Reduces movement speed and causes bleeding damage + Crippled, } #[cfg(not(target_arch = "wasm32"))] @@ -54,6 +56,7 @@ impl BuffKind { BuffKind::Invulnerability => true, BuffKind::ProtectingWard => true, BuffKind::Burning => false, + BuffKind::Crippled => false, } } @@ -118,6 +121,8 @@ pub enum BuffEffect { kind: ModifierKind, target_fraction: f32, }, + /// Modifies move speed of target + MovementSpeed(f32), } /// Actual de/buff. @@ -174,6 +179,8 @@ impl Buff { cat_ids: Vec, source: BuffSource, ) -> Self { + // Normalized nonlinear scaling + let nn_scaling = |a| a / (a + 0.5); let (effects, time) = match kind { BuffKind::Bleeding => ( vec![BuffEffect::HealthChangeOverTime { @@ -235,7 +242,7 @@ impl Buff { // Causes non-linearity in effect strength, but necessary to allow for tool // power and other things to affect the strength. 0.5 also still provides 50% // damage reduction. - data.strength / (0.5 + data.strength), + nn_scaling(data.strength), )], data.duration, ), @@ -247,6 +254,17 @@ impl Buff { }], data.duration, ), + BuffKind::Crippled => ( + vec![ + BuffEffect::MovementSpeed(1.0 - nn_scaling(data.strength)), + BuffEffect::HealthChangeOverTime { + rate: -data.strength * 100.0, + accumulated: 0.0, + kind: ModifierKind::Additive, + }, + ], + data.duration, + ), }; Buff { kind, diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index 55a49ae343..b7d428102d 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -25,6 +25,7 @@ pub struct Stats { pub name: String, pub damage_reduction: f32, pub max_health_modifier: f32, + pub move_speed_modifier: f32, } impl Stats { @@ -33,6 +34,7 @@ impl Stats { name, damage_reduction: 0.0, max_health_modifier: 1.0, + move_speed_modifier: 1.0, } } @@ -43,6 +45,7 @@ impl Stats { name: "".to_owned(), damage_reduction: 0.0, max_health_modifier: 1.0, + move_speed_modifier: 1.0, } } @@ -50,6 +53,7 @@ impl Stats { pub fn reset_temp_modifiers(&mut self) { self.damage_reduction = 0.0; self.max_health_modifier = 1.0; + self.move_speed_modifier = 1.0; } } diff --git a/common/src/states/basic_melee.rs b/common/src/states/basic_melee.rs index 7346190829..844c3ea2f4 100644 --- a/common/src/states/basic_melee.rs +++ b/common/src/states/basic_melee.rs @@ -29,6 +29,8 @@ pub struct StaticData { pub range: f32, /// Max angle (45.0 will give you a 90.0 angle window) pub max_angle: f32, + /// Adds an effect onto the main damage of the attack + pub damage_effect: Option, /// What key is used to press ability pub ability_info: AbilityInfo, } @@ -97,15 +99,20 @@ impl CharacterBehavior for Data { .with_requirement(CombatRequirement::AnyDamage); let energy = AttackEffect::new(None, CombatEffect::EnergyReward(50.0)) .with_requirement(CombatRequirement::AnyDamage); - let buff = CombatEffect::Buff(CombatBuff::default_physical()); - let damage = AttackDamage::new( + let mut damage = AttackDamage::new( Damage { source: DamageSource::Melee, value: self.static_data.base_damage as f32, }, Some(GroupTarget::OutOfGroup), - ) - .with_effect(buff); + ); + match self.static_data.damage_effect { + Some(effect) => damage = damage.with_effect(effect), + None => { + let buff = CombatEffect::Buff(CombatBuff::default_physical()); + damage = damage.with_effect(buff); + }, + } let (crit_chance, crit_mult) = get_crit_data(data, self.static_data.ability_info); let attack = Attack::default() diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index f7f0a58e39..9e4fe43d9f 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -71,7 +71,6 @@ 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.1); match self.stage_section { diff --git a/common/src/states/spin_melee.rs b/common/src/states/spin_melee.rs index 232a84b1b1..8730d86f34 100644 --- a/common/src/states/spin_melee.rs +++ b/common/src/states/spin_melee.rs @@ -175,7 +175,6 @@ impl CharacterBehavior for Data { }, 0.1, ); - handle_orientation(data, &mut update, 1.0); } // Swings diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index b8fadff6c0..e50d70cf81 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -243,6 +243,8 @@ pub fn handle_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) { /// Updates components to move player as if theyre on ground or in air #[allow(clippy::assign_op_pattern)] // TODO: Pending review in #587 fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) { + let efficiency = efficiency * data.stats.move_speed_modifier; + let accel = if data.physics.on_ground { data.body.base_accel() } else { @@ -267,6 +269,8 @@ pub fn handle_forced_movement( movement: ForcedMovement, efficiency: f32, ) { + let efficiency = efficiency * data.stats.move_speed_modifier; + match movement { ForcedMovement::Forward { strength } => { if let Some(accel) = data.physics.on_ground.then_some(data.body.base_accel()) { @@ -324,6 +328,7 @@ pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, efficiency: /// Updates components to move player as if theyre swimming fn swim_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, submersion: f32) -> bool { + let efficiency = efficiency * data.stats.move_speed_modifier; if let Some(force) = data.body.swim_thrust() { let force = efficiency * force; let mut water_accel = force / data.mass.0; @@ -361,6 +366,8 @@ fn swim_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, submers /// Updates components to move entity as if it's flying pub fn fly_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) -> bool { + let efficiency = efficiency * data.stats.move_speed_modifier; + let glider = match data.character { CharacterState::Glide(data) => Some(data), _ => None, diff --git a/common/systems/src/buff.rs b/common/systems/src/buff.rs index 9d379af810..71137c4540 100644 --- a/common/systems/src/buff.rs +++ b/common/systems/src/buff.rs @@ -189,6 +189,9 @@ impl<'a> System<'a> for Sys { stat.max_health_modifier *= current_fraction; } }, + BuffEffect::MovementSpeed(ms) => { + stat.move_speed_modifier *= *ms; + }, }; } } diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 339e5a2cbf..3fe30786da 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -3626,6 +3626,8 @@ pub fn get_buff_image(buff: BuffKind, imgs: &Imgs) -> conrod_core::image::Id { BuffKind::Bleeding { .. } => imgs.debuff_bleed_0, BuffKind::Cursed { .. } => imgs.debuff_skull_0, BuffKind::Burning { .. } => imgs.debuff_burning_0, + // TODO: Get buff icon + BuffKind::Crippled { .. } => imgs.debuff_bleed_0, } } @@ -3644,6 +3646,7 @@ pub fn get_buff_title(buff: BuffKind, localized_strings: &Localization) -> &str BuffKind::Bleeding { .. } => localized_strings.get("buff.title.bleed"), BuffKind::Cursed { .. } => localized_strings.get("buff.title.cursed"), BuffKind::Burning { .. } => localized_strings.get("buff.title.burn"), + BuffKind::Crippled { .. } => localized_strings.get("buff.title.crippled"), } } @@ -3674,6 +3677,7 @@ pub fn get_buff_desc(buff: BuffKind, data: BuffData, localized_strings: &Localiz BuffKind::Bleeding { .. } => Cow::Borrowed(localized_strings.get("buff.desc.bleed")), BuffKind::Cursed { .. } => Cow::Borrowed(localized_strings.get("buff.desc.cursed")), BuffKind::Burning { .. } => Cow::Borrowed(localized_strings.get("buff.desc.burn")), + BuffKind::Crippled { .. } => Cow::Borrowed(localized_strings.get("buff.desc.crippled")), } } diff --git a/voxygen/src/hud/util.rs b/voxygen/src/hud/util.rs index c61eee530f..e9cdc8d0cf 100644 --- a/voxygen/src/hud/util.rs +++ b/voxygen/src/hud/util.rs @@ -118,7 +118,8 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> String { | BuffKind::Burning | BuffKind::CampfireHeal | BuffKind::Cursed - | BuffKind::ProtectingWard => continue, + | BuffKind::ProtectingWard + | BuffKind::Crippled => continue, }; write!(&mut description, "{}", buff_desc).unwrap(); @@ -138,7 +139,8 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> String { | BuffKind::Potion | BuffKind::CampfireHeal | BuffKind::Cursed - | BuffKind::ProtectingWard => continue, + | BuffKind::ProtectingWard + | BuffKind::Crippled => continue, } } else if let BuffKind::Saturation | BuffKind::Regeneration = buff.kind { i18n.get("buff.text.every_second").to_string() From ac57c7fc3198950119dec8344953a0bbca78fb23 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 16 Apr 2021 14:54:46 -0400 Subject: [PATCH 04/19] Cleave functional --- .../abilities/custom/minotaur/charge.ron | 6 ++-- .../abilities/custom/minotaur/cleave.ron | 30 +++++++++---------- .../custom/minotaur/cripplingstrike.ron | 2 +- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/assets/common/abilities/custom/minotaur/charge.ron b/assets/common/abilities/custom/minotaur/charge.ron index 6563de650a..1d0836bfed 100644 --- a/assets/common/abilities/custom/minotaur/charge.ron +++ b/assets/common/abilities/custom/minotaur/charge.ron @@ -1,12 +1,12 @@ DashMelee( energy_cost: 0, - base_damage: 500, - scaled_damage: 2000, + base_damage: 300, + scaled_damage: 1200, base_poise_damage: 25, scaled_poise_damage: 100, base_knockback: 10.0, scaled_knockback: 30.0, - range: 7.5, + range: 5.0, angle: 90.0, energy_drain: 0, forward_speed: 5.0, diff --git a/assets/common/abilities/custom/minotaur/cleave.ron b/assets/common/abilities/custom/minotaur/cleave.ron index 6563de650a..486ffed3fb 100644 --- a/assets/common/abilities/custom/minotaur/cleave.ron +++ b/assets/common/abilities/custom/minotaur/cleave.ron @@ -1,19 +1,17 @@ -DashMelee( +ChargedMelee( energy_cost: 0, - base_damage: 500, - scaled_damage: 2000, - base_poise_damage: 25, - scaled_poise_damage: 100, - base_knockback: 10.0, - scaled_knockback: 30.0, - range: 7.5, - angle: 90.0, energy_drain: 0, - forward_speed: 5.0, - buildup_duration: 0.4, - charge_duration: 4.0, - swing_duration: 0.1, + initial_damage: 200, + scaled_damage: 800, + initial_poise_damage: 50, + scaled_poise_damage: 150, + initial_knockback: 0.0, + scaled_knockback: 0.0, + range: 5.0, + max_angle: 45.0, + speed: 1.0, + charge_duration: 2.0, + swing_duration: 0.2, + hit_timing: 0.8, recover_duration: 0.5, - infinite_charge: false, - is_interruptible: false, -) \ No newline at end of file +) diff --git a/assets/common/abilities/custom/minotaur/cripplingstrike.ron b/assets/common/abilities/custom/minotaur/cripplingstrike.ron index fbc946b9ed..8376a1f147 100644 --- a/assets/common/abilities/custom/minotaur/cripplingstrike.ron +++ b/assets/common/abilities/custom/minotaur/cripplingstrike.ron @@ -5,7 +5,7 @@ BasicMelee( recover_duration: 0.6, base_damage: 250.0, base_poise_damage: 60.0, - knockback: 25.0, + knockback: 15.0, range: 5.0, max_angle: 90.0, damage_effect: Some(Buff(( From 2e97fad3d811063b35a52fb005f1055ab4e5b097 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 24 Apr 2021 15:01:36 -0400 Subject: [PATCH 05/19] Added frenzy ability to minotaur. Added self-buff character state. Added frenzied buff kind. Added better comments on each buff kind. --- .../abilities/custom/minotaur/frenzy.ron | 24 +--- assets/voxygen/i18n/en/buff.ron | 2 + common/src/comp/ability.rs | 65 ++++++++- common/src/comp/buff.rs | 31 +++++ common/src/comp/character_state.rs | 4 + common/src/states/mod.rs | 1 + common/src/states/self_buff.rs | 131 ++++++++++++++++++ common/systems/src/character_behavior.rs | 2 + common/systems/src/stats.rs | 3 +- voxygen/src/hud/mod.rs | 4 + voxygen/src/hud/util.rs | 6 +- 11 files changed, 247 insertions(+), 26 deletions(-) create mode 100644 common/src/states/self_buff.rs diff --git a/assets/common/abilities/custom/minotaur/frenzy.ron b/assets/common/abilities/custom/minotaur/frenzy.ron index 6563de650a..4a014d42bb 100644 --- a/assets/common/abilities/custom/minotaur/frenzy.ron +++ b/assets/common/abilities/custom/minotaur/frenzy.ron @@ -1,19 +1,9 @@ -DashMelee( +SelfBuff( + buildup_duration: 0.5, + cast_duration: 0.25, + recover_duration: 0.25, + buff_kind: Frenzied, + buff_strength: 0.5, + buff_duration: None, energy_cost: 0, - base_damage: 500, - scaled_damage: 2000, - base_poise_damage: 25, - scaled_poise_damage: 100, - base_knockback: 10.0, - scaled_knockback: 30.0, - range: 7.5, - angle: 90.0, - energy_drain: 0, - forward_speed: 5.0, - buildup_duration: 0.4, - charge_duration: 4.0, - swing_duration: 0.1, - recover_duration: 0.5, - infinite_charge: false, - is_interruptible: false, ) \ No newline at end of file diff --git a/assets/voxygen/i18n/en/buff.ron b/assets/voxygen/i18n/en/buff.ron index cbd6d30f19..6f6047386e 100644 --- a/assets/voxygen/i18n/en/buff.ron +++ b/assets/voxygen/i18n/en/buff.ron @@ -19,6 +19,8 @@ "buff.desc.invulnerability": "You cannot be damaged by any attack.", "buff.title.protectingward": "Protecting Ward", "buff.desc.protectingward": "You are protected, somewhat, from attacks.", + "buff.title.frenzied": "Frenzied", + "buff.desc.frenzied": "You are imbued with nunnatural speed and can ignore minor injuries." // Debuffs "buff.title.bleed": "Bleeding", "buff.desc.bleed": "Inflicts regular damage.", diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 5ec986c363..96b2f9d3fa 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -2,8 +2,8 @@ use crate::{ assets::{self, Asset}, combat::{self, CombatEffect, Knockback}, comp::{ - aura, beam, inventory::item::tool::ToolKind, projectile::ProjectileConstructor, skills, - Body, CharacterState, EnergySource, LightEmitter, StateUpdate, + aura, beam, buff, inventory::item::tool::ToolKind, projectile::ProjectileConstructor, + skills, Body, CharacterState, EnergySource, LightEmitter, StateUpdate, }, states::{ behavior::JoinData, @@ -30,6 +30,7 @@ pub enum CharacterAbilityType { BasicBeam, RepeaterRanged, BasicAura, + SelfBuff, } impl From<&CharacterState> for CharacterAbilityType { @@ -49,6 +50,7 @@ impl From<&CharacterState> for CharacterAbilityType { CharacterState::BasicBeam(_) => Self::BasicBeam, CharacterState::RepeaterRanged(_) => Self::RepeaterRanged, CharacterState::BasicAura(_) => Self::BasicAura, + CharacterState::SelfBuff(_) => Self::SelfBuff, _ => Self::BasicMelee, } } @@ -269,6 +271,15 @@ pub enum CharacterAbility { summon_amount: u32, summon_info: basic_summon::SummonInfo, }, + SelfBuff { + buildup_duration: f32, + cast_duration: f32, + recover_duration: f32, + buff_kind: buff::BuffKind, + buff_strength: f32, + buff_duration: Option, + energy_cost: f32, + }, } impl Default for CharacterAbility { @@ -315,7 +326,8 @@ impl CharacterAbility { | CharacterAbility::ChargedMelee { energy_cost, .. } | CharacterAbility::Shockwave { energy_cost, .. } | CharacterAbility::BasicAura { energy_cost, .. } - | CharacterAbility::BasicBlock { energy_cost, .. } => update + | CharacterAbility::BasicBlock { energy_cost, .. } + | CharacterAbility::SelfBuff { energy_cost, .. } => update .energy .try_change_by(-(*energy_cost as i32), EnergySource::Ability) .is_ok(), @@ -336,7 +348,11 @@ impl CharacterAbility { .is_ok() }, CharacterAbility::HealingBeam { .. } => data.combo.counter() > 0, - _ => true, + CharacterAbility::ComboMelee { .. } + | CharacterAbility::Boost { .. } + | CharacterAbility::BasicBeam { .. } + | CharacterAbility::Blink { .. } + | CharacterAbility::BasicSummon { .. } => true, } } @@ -588,6 +604,18 @@ impl CharacterAbility { *cast_duration /= speed; *recover_duration /= speed; }, + SelfBuff { + ref mut buff_strength, + ref mut buildup_duration, + ref mut cast_duration, + ref mut recover_duration, + .. + } => { + *buff_strength *= power; + *buildup_duration /= speed; + *cast_duration /= speed; + *recover_duration /= speed; + }, } self } @@ -607,7 +635,8 @@ impl CharacterAbility { | Shockwave { energy_cost, .. } | HealingBeam { energy_cost, .. } | BasicAura { energy_cost, .. } - | BasicBlock { energy_cost, .. } => *energy_cost as u32, + | BasicBlock { energy_cost, .. } + | SelfBuff { energy_cost, .. } => *energy_cost as u32, BasicBeam { energy_drain, .. } => { if *energy_drain > f32::EPSILON { 1 @@ -615,7 +644,10 @@ impl CharacterAbility { 0 } }, - Boost { .. } | ComboMelee { .. } | Blink { .. } | BasicSummon { .. } => 0, + Boost { .. } + | ComboMelee { .. } + | Blink { .. } + | BasicSummon { .. } => 0, } } @@ -1661,6 +1693,27 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState { timer: Duration::default(), stage_section: StageSection::Buildup, }), + CharacterAbility::SelfBuff { + buildup_duration, + cast_duration, + recover_duration, + buff_kind, + buff_strength, + buff_duration, + energy_cost: _, + } => CharacterState::SelfBuff(self_buff::Data { + static_data: self_buff::StaticData { + buildup_duration: Duration::from_secs_f32(*buildup_duration), + cast_duration: Duration::from_secs_f32(*cast_duration), + recover_duration: Duration::from_secs_f32(*recover_duration), + buff_kind: *buff_kind, + buff_strength: *buff_strength, + buff_duration: buff_duration.map(Duration::from_secs_f32), + ability_info, + }, + timer: Duration::default(), + stage_section: StageSection::Buildup, + }), } } } diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index f93c419855..131a6af390 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -15,29 +15,48 @@ use std::{cmp::Ordering, time::Duration}; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, PartialOrd, Ord)] pub enum BuffKind { /// Does damage to a creature over time + /// Strength should be 10x the DPS of the debuff Burning, /// Restores health/time for some period + /// Strength should be 10x the healing per second Regeneration, /// Restores health/time for some period for consumables + /// Strength should be 10x the healing per second Saturation, /// Lowers health over time for some duration + /// Strength should be 10x the DPS of the debuff Bleeding, /// Lower a creature's max health over time + /// Strength only affects the target max health, 0.5 targets 50% of base + /// max, 1.0 targets 100% of base max Cursed, /// Applied when drinking a potion + /// Strength should be 10x the healing per second Potion, /// Applied when sitting at a campfire + /// Strength is fraction of health resotred per second CampfireHeal, /// Raises maximum stamina + /// Strength should be 10x the effect to max energy IncreaseMaxEnergy, /// Raises maximum health + /// Strength should be 10x the effect to max health IncreaseMaxHealth, /// Makes you immune to attacks + /// Strength does not affect this buff Invulnerability, /// Reduces incoming damage + /// Strength scales the damage reduction non-linearly. 0.5 provides 50% DR, + /// 1.0 provides 67% DR ProtectingWard, /// Reduces movement speed and causes bleeding damage + /// Strength scales the movement speed debuff non-linearly. 0.5 is 50% + /// speed, 1.0 is 33% speed. Bleeding is at 10x the value of the strength. Crippled, + /// Increases movement speed and gives health regeneration + /// Strength scales the movement speed linearly. 0.5 is 150% speed, 1.0 is + /// 200% speed. Provides regeneration at 10x the value of the strength + Frenzied, } #[cfg(not(target_arch = "wasm32"))] @@ -57,6 +76,7 @@ impl BuffKind { BuffKind::ProtectingWard => true, BuffKind::Burning => false, BuffKind::Crippled => false, + BuffKind::Frenzied => true, } } @@ -265,6 +285,17 @@ impl Buff { ], data.duration, ), + BuffKind::Frenzied => ( + vec![ + BuffEffect::MovementSpeed(1.0 + data.strength), + BuffEffect::HealthChangeOverTime { + rate: data.strength * 100.0, + accumulated: 0.0, + kind: ModifierKind::Additive, + }, + ], + data.duration, + ), }; Buff { kind, diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index 4b9abe1cb2..d73be47340 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -99,6 +99,8 @@ pub enum CharacterState { Blink(blink::Data), /// Summons creatures that fight for the caster BasicSummon(basic_summon::Data), + /// Inserts a buff on the caster + SelfBuff(self_buff::Data), } impl CharacterState { @@ -120,6 +122,7 @@ impl CharacterState { | CharacterState::BasicBeam(_) | CharacterState::BasicAura(_) | CharacterState::HealingBeam(_) + | CharacterState::SelfBuff(_) ) } @@ -143,6 +146,7 @@ impl CharacterState { | CharacterState::BasicBeam(_) | CharacterState::BasicAura(_) | CharacterState::HealingBeam(_) + | CharacterState::SelfBuff(_) ) } diff --git a/common/src/states/mod.rs b/common/src/states/mod.rs index 15cb6c72d6..30b86e3766 100644 --- a/common/src/states/mod.rs +++ b/common/src/states/mod.rs @@ -21,6 +21,7 @@ pub mod idle; pub mod leap_melee; pub mod repeater_ranged; pub mod roll; +pub mod self_buff; pub mod shockwave; pub mod sit; pub mod sneak; diff --git a/common/src/states/self_buff.rs b/common/src/states/self_buff.rs new file mode 100644 index 0000000000..85a99e46ab --- /dev/null +++ b/common/src/states/self_buff.rs @@ -0,0 +1,131 @@ +use crate::{ + comp::{ + buff::{Buff, BuffChange, BuffData, BuffKind, BuffSource}, + CharacterState, StateUpdate, + }, + event::ServerEvent, + states::{ + behavior::{CharacterBehavior, JoinData}, + utils::*, + }, +}; +use serde::{Deserialize, Serialize}; +use std::time::Duration; + +/// Separated out to condense update portions of character state +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct StaticData { + /// How long until state should create the aura + pub buildup_duration: Duration, + /// How long the state is creating an aura + pub cast_duration: Duration, + /// How long the state has until exiting + pub recover_duration: Duration, + /// What kind of buff is created + pub buff_kind: BuffKind, + /// Strength of the created buff + pub buff_strength: f32, + /// How long buff lasts + pub buff_duration: Option, + /// What key is used to press ability + pub ability_info: AbilityInfo, +} + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Data { + /// Struct containing data that does not change over the course of the + /// character state + pub static_data: StaticData, + /// Timer for each stage + pub timer: Duration, + /// What section the character stage is in + pub stage_section: StageSection, +} + +impl CharacterBehavior for Data { + fn behavior(&self, data: &JoinData) -> StateUpdate { + let mut update = StateUpdate::from(data); + + handle_move(data, &mut update, 0.8); + handle_jump(data, &mut update, 1.0); + + match self.stage_section { + StageSection::Buildup => { + if self.timer < self.static_data.buildup_duration { + // Build up + update.character = CharacterState::SelfBuff(Data { + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + ..*self + }); + } else { + // Creates buff + let buff = Buff::new( + self.static_data.buff_kind, + BuffData { + strength: self.static_data.buff_strength, + duration: self.static_data.buff_duration, + }, + Vec::new(), + BuffSource::Character { by: *data.uid }, + ); + update.server_events.push_front(ServerEvent::Buff { + entity: data.entity, + buff_change: BuffChange::Add(buff), + }); + // Build up + update.character = CharacterState::SelfBuff(Data { + timer: Duration::default(), + stage_section: StageSection::Cast, + ..*self + }); + } + }, + StageSection::Cast => { + if self.timer < self.static_data.cast_duration { + // Cast + update.character = CharacterState::SelfBuff(Data { + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + ..*self + }); + } else { + update.character = CharacterState::SelfBuff(Data { + timer: Duration::default(), + stage_section: StageSection::Recover, + ..*self + }); + } + }, + StageSection::Recover => { + if self.timer < self.static_data.recover_duration { + update.character = CharacterState::SelfBuff(Data { + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + ..*self + }); + } else { + // Done + update.character = CharacterState::Wielding; + } + }, + _ => { + // If it somehow ends up in an incorrect stage section + update.character = CharacterState::Wielding; + }, + } + + // At end of state logic so an interrupt isn't overwritten + if !input_is_pressed(data, self.static_data.ability_info.input) { + handle_state_interrupt(data, &mut update, false); + } + + update + } +} diff --git a/common/systems/src/character_behavior.rs b/common/systems/src/character_behavior.rs index d93791c78e..a97350888b 100644 --- a/common/systems/src/character_behavior.rs +++ b/common/systems/src/character_behavior.rs @@ -341,6 +341,7 @@ impl<'a> System<'a> for Sys { CharacterState::HealingBeam(data) => data.handle_event(&j, action), CharacterState::Blink(data) => data.handle_event(&j, action), CharacterState::BasicSummon(data) => data.handle_event(&j, action), + CharacterState::SelfBuff(data) => data.handle_event(&j, action), }; local_emitter.append(&mut state_update.local_events); server_emitter.append(&mut state_update.server_events); @@ -395,6 +396,7 @@ impl<'a> System<'a> for Sys { CharacterState::HealingBeam(data) => data.behavior(&j), CharacterState::Blink(data) => data.behavior(&j), CharacterState::BasicSummon(data) => data.behavior(&j), + CharacterState::SelfBuff(data) => data.behavior(&j), }; local_emitter.append(&mut state_update.local_events); diff --git a/common/systems/src/stats.rs b/common/systems/src/stats.rs index 4d999387db..18ef179826 100644 --- a/common/systems/src/stats.rs +++ b/common/systems/src/stats.rs @@ -248,7 +248,8 @@ impl<'a> System<'a> for Sys { | CharacterState::BasicAura { .. } | CharacterState::HealingBeam { .. } | CharacterState::Blink { .. } - | CharacterState::BasicSummon { .. } => { + | CharacterState::BasicSummon { .. } + | CharacterState::SelfBuff { .. } => { if energy.get_unchecked().regen_rate != 0.0 { energy.get_mut_unchecked().regen_rate = 0.0 } diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 3fe30786da..83ad74a6d5 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -3622,6 +3622,8 @@ pub fn get_buff_image(buff: BuffKind, imgs: &Imgs) -> conrod_core::image::Id { BuffKind::IncreaseMaxHealth { .. } => imgs.buff_healthplus_0, BuffKind::Invulnerability => imgs.buff_invincibility_0, BuffKind::ProtectingWard => imgs.buff_dmg_red_0, + // TODO: Get buff icon + BuffKind::Frenzied { .. } => imgs.buff_invincibility_0, // Debuffs BuffKind::Bleeding { .. } => imgs.debuff_bleed_0, BuffKind::Cursed { .. } => imgs.debuff_skull_0, @@ -3642,6 +3644,7 @@ pub fn get_buff_title(buff: BuffKind, localized_strings: &Localization) -> &str BuffKind::IncreaseMaxEnergy { .. } => localized_strings.get("buff.title.staminaup"), BuffKind::Invulnerability => localized_strings.get("buff.title.invulnerability"), BuffKind::ProtectingWard => localized_strings.get("buff.title.protectingward"), + BuffKind::Frenzied => localized_strings.get("buff.title.frenzied"), // Debuffs BuffKind::Bleeding { .. } => localized_strings.get("buff.title.bleed"), BuffKind::Cursed { .. } => localized_strings.get("buff.title.cursed"), @@ -3673,6 +3676,7 @@ pub fn get_buff_desc(buff: BuffKind, data: BuffData, localized_strings: &Localiz BuffKind::ProtectingWard => { Cow::Borrowed(localized_strings.get("buff.desc.protectingward")) }, + BuffKind::Frenzied => Cow::Borrowed(localized_strings.get("buff.desc.frenzied")), // Debuffs BuffKind::Bleeding { .. } => Cow::Borrowed(localized_strings.get("buff.desc.bleed")), BuffKind::Cursed { .. } => Cow::Borrowed(localized_strings.get("buff.desc.cursed")), diff --git a/voxygen/src/hud/util.rs b/voxygen/src/hud/util.rs index e9cdc8d0cf..68271e7ebb 100644 --- a/voxygen/src/hud/util.rs +++ b/voxygen/src/hud/util.rs @@ -119,7 +119,8 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> String { | BuffKind::CampfireHeal | BuffKind::Cursed | BuffKind::ProtectingWard - | BuffKind::Crippled => continue, + | BuffKind::Crippled + | BuffKind::Frenzied => continue, }; write!(&mut description, "{}", buff_desc).unwrap(); @@ -140,7 +141,8 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> String { | BuffKind::CampfireHeal | BuffKind::Cursed | BuffKind::ProtectingWard - | BuffKind::Crippled => continue, + | BuffKind::Crippled + | BuffKind::Frenzied => continue, } } else if let BuffKind::Saturation | BuffKind::Regeneration = buff.kind { i18n.get("buff.text.every_second").to_string() From 23bace6a0c86a6f14ce864abf2712a97d4f39c2a Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 24 Apr 2021 15:40:23 -0400 Subject: [PATCH 06/19] Fix charge being broken. --- assets/common/abilities/custom/minotaur/charge.ron | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/common/abilities/custom/minotaur/charge.ron b/assets/common/abilities/custom/minotaur/charge.ron index 1d0836bfed..07871af78a 100644 --- a/assets/common/abilities/custom/minotaur/charge.ron +++ b/assets/common/abilities/custom/minotaur/charge.ron @@ -14,6 +14,6 @@ DashMelee( charge_duration: 4.0, swing_duration: 0.1, recover_duration: 0.5, - infinite_charge: false, + charge_through: false, is_interruptible: false, ) \ No newline at end of file From 8860e6041509f8d69e6453d805114f44c2c07e65 Mon Sep 17 00:00:00 2001 From: jshipsey Date: Sat, 24 Apr 2021 21:45:58 -0400 Subject: [PATCH 07/19] anims --- .../abilities/custom/minotaur/cleave.ron | 2 +- .../custom/minotaur/cripplingstrike.ron | 2 +- .../abilities/custom/minotaur/frenzy.ron | 4 +- .../voxygen/voxel/biped_weapon_manifest.ron | 2 +- .../voxel/weapon/axe/2haxe_minotaur.vox | Bin 3652 -> 3484 bytes common/src/comp/ability.rs | 5 +- voxygen/anim/src/biped_large/alpha.rs | 36 +++- voxygen/anim/src/biped_large/chargemelee.rs | 159 +++++++++++++++++ voxygen/anim/src/biped_large/dash.rs | 67 ++++++- voxygen/anim/src/biped_large/idle.rs | 5 +- voxygen/anim/src/biped_large/jump.rs | 3 +- voxygen/anim/src/biped_large/mod.rs | 31 ++-- voxygen/anim/src/biped_large/run.rs | 11 +- voxygen/anim/src/biped_large/selfbuff.rs | 163 ++++++++++++++++++ voxygen/anim/src/biped_large/stunned.rs | 21 ++- voxygen/anim/src/biped_large/wield.rs | 26 ++- voxygen/src/scene/figure/load.rs | 67 ++++--- voxygen/src/scene/figure/mod.rs | 87 +++++++++- 18 files changed, 624 insertions(+), 67 deletions(-) create mode 100644 voxygen/anim/src/biped_large/chargemelee.rs create mode 100644 voxygen/anim/src/biped_large/selfbuff.rs diff --git a/assets/common/abilities/custom/minotaur/cleave.ron b/assets/common/abilities/custom/minotaur/cleave.ron index 486ffed3fb..f08f594881 100644 --- a/assets/common/abilities/custom/minotaur/cleave.ron +++ b/assets/common/abilities/custom/minotaur/cleave.ron @@ -11,7 +11,7 @@ ChargedMelee( max_angle: 45.0, speed: 1.0, charge_duration: 2.0, - swing_duration: 0.2, + swing_duration: 0.1, hit_timing: 0.8, recover_duration: 0.5, ) diff --git a/assets/common/abilities/custom/minotaur/cripplingstrike.ron b/assets/common/abilities/custom/minotaur/cripplingstrike.ron index 8376a1f147..f363a35a06 100644 --- a/assets/common/abilities/custom/minotaur/cripplingstrike.ron +++ b/assets/common/abilities/custom/minotaur/cripplingstrike.ron @@ -1,7 +1,7 @@ BasicMelee( energy_cost: 0, buildup_duration: 0.3, - swing_duration: 0.2, + swing_duration: 0.1, recover_duration: 0.6, base_damage: 250.0, base_poise_damage: 60.0, diff --git a/assets/common/abilities/custom/minotaur/frenzy.ron b/assets/common/abilities/custom/minotaur/frenzy.ron index 4a014d42bb..5d905a28ac 100644 --- a/assets/common/abilities/custom/minotaur/frenzy.ron +++ b/assets/common/abilities/custom/minotaur/frenzy.ron @@ -1,6 +1,6 @@ SelfBuff( - buildup_duration: 0.5, - cast_duration: 0.25, + buildup_duration: 0.25, + cast_duration: 0.8, recover_duration: 0.25, buff_kind: Frenzied, buff_strength: 0.5, diff --git a/assets/voxygen/voxel/biped_weapon_manifest.ron b/assets/voxygen/voxel/biped_weapon_manifest.ron index ae60874a09..57dfec123d 100644 --- a/assets/voxygen/voxel/biped_weapon_manifest.ron +++ b/assets/voxygen/voxel/biped_weapon_manifest.ron @@ -1043,7 +1043,7 @@ color: None ), "common.items.npc_weapons.axe.minotaur_axe": ( - vox_spec: ("weapon.axe.2haxe_minotaur", (-2.5, -9.0, -6.0)), + vox_spec: ("weapon.axe.2haxe_minotaur", (-2.5, -9.0, -8.0)), color: None ), "common.items.npc_weapons.hammer.yeti_hammer": ( diff --git a/assets/voxygen/voxel/weapon/axe/2haxe_minotaur.vox b/assets/voxygen/voxel/weapon/axe/2haxe_minotaur.vox index 5bc91af3fed771d7e6ad5d1c6e1965c50d843d5e..ac28d01a8891afb5d6225c5eb70a90e048f817a5 100644 GIT binary patch delta 2032 zcmW-hO_C!u5QUZbROR}&-SgMo{aNQ0Sgwh02Tx=*uG0`>9T7vK?I8lcAS9V z3LJyO@M#?JETxp0O1*rgf0utQ`k#OJu>B*1@ZC4>zh?-)wITfY{`hT^41O870q?+v zUytuUluY>jUzc^Ys!@fDH zxap6=5Q}0{I0Z} z2dnoNt3b13zWZcVzr(<>CZO7WvIfT*RG?f_<$;P1RK7mhWPJ?f`q?IjQ%LK@hP@TH z+nhu4DR-=G0b{v8TeW7sKZk;tV#Tf5tB6x7U`0`&FJE)WD-O6N=oY6}*l&(Dp_q&+ zbE=$BWJdKlfs+(`zy{@;Qz&;sDE7~x1jS|$Ezsu{bmZyIp*jrKtS?r)rkH!qSe&hX z8mw4y=H0osa*5;O6ec+4Y?OE0e~%%0crmD0>)Ua~NU<>irONFiF@A zv0|(kiHXFDT#=mOut*V+0!_P1q}WK&CRo>|zgWkOI&Ro)*<_=G`j`S}N#xcs1#Pi6 zLrgb>HbI}DQ6vL@tp>>QF7(B-$m~Cfeui(v7y^@>>NACrl&r^XTp5K+JwC(fqBDP!+wUHVQ1JG zcG5=DPxHVCnl{uBnL_|5PW delta 2203 zcmW-hNsb#w5JmGxWEE>BsaY+lN6ze)bpUU)@Inh)3j>Bs@-DS*k_9gWcp>-}x`G!z zmS2j%XJ*D!kr5gHpEv)${rQj2U#|ZSA^iIB({C){Ll?sDpLV}A>A)`oPrwK8<4mzCU^nn(fiE?J+i+W6VIk zKE@o35?04pu~w|3#bc}%kDfoU-yFSWt*|fGkMh+i7VF1Yu8#8MNxnF#TZ0u?qC?&x zi^+a@R9yG`C8s5V#W5BOl9-*m0lo$+usm6Lvv-0y!JJ@DFei``$m1Fyi`W&ndyh#z zKY6=3T6wqg7JZAp#iw0hbGP>veFmC-j^J|V*@lnY9;~=ISowBm<<-uLE6#8CR=(SL zll0e=@*3H@gO5lg2N}UftCO`4gXgPn*1R9A{%NorWbEU^pklihRkreS@7W6bxlxuwH%hip(1fYaA*Z8|-ROfpWg{Vsr3vLp$etAI*2MoIeK2 z98!5{t5RD>n|(}n#RA(I?Oz;X@+nt`-isxQ6^ix2t2z7iAr|vTFJ?P0(N&v+co%^d z1zKd?^TPz0pW$!BF_N?C8lMdnTpx_@7~ivE)$@lD znb>qS7@1j_lrs$3PnUy{y-gRa>9&_U(PzPglvSaNnqa~YtUz$GtL?3jB|P$>HRcY zR?y6mgJ#AGnmgnmzd2c*aLXRl*JtZ<{^~0}44Rv>wV*-SCg9Z0czBdLLq47HsE`Lr z8IiYqq$Qb_WLlDGNxa>hEh3M|Bl3tmB9F*B;&u3SJo*lOw>e3p{XhFd>l%ADWQJgzrpJ zg7+i?I_!MgpG^p}d&&kPW9}{R_yg3Kh)f1`pkV=4N12pT2y%J+VG7d`x zXxAYnhm;)B5sVd};Q$Q>XgE}hM-fEC5Of@%V-Z8d5HUmyLC+$Fh@ljtNimoVm^MJ! zeSoh+;%i1mykha11-pq!5bP${O)#5aF2P(%Bgl-4Sr;=eW?yiCplw0hg0_`7gV`6e zAK(%(^J3=3%nPm&BQHiil$##s1&7&Q%zJ>P#JmSsOw79=4#8APa@bB4^9}n678GnK zSW&Q}U`fH2f;9zu3KkV?Dp*ypt6*6{w}N)9cn!V31Q!rfe*po#gyUZ!cmwIY;rt2$ zdQB?;dq?Kz92>{hiwn*dFx^YeuSpWH7c!v}Ho{i;2wxFH#IoWUvS)njIUjzG{KY|i z`2qn*2ZV-!17YOI9G!6VA9&6=IZsJ;44$xmLc(KWOgKL!&Qs14;!KGF*bAA^2^(Q6 he1xxvu@%8QfrBG-l#Y>O>^M2jP7p7r-~TGx_&+lrY_b3V diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 96b2f9d3fa..9e0525b3e0 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -644,10 +644,7 @@ impl CharacterAbility { 0 } }, - Boost { .. } - | ComboMelee { .. } - | Blink { .. } - | BasicSummon { .. } => 0, + Boost { .. } | ComboMelee { .. } | Blink { .. } | BasicSummon { .. } => 0, } } diff --git a/voxygen/anim/src/biped_large/alpha.rs b/voxygen/anim/src/biped_large/alpha.rs index 27d6f70049..c5ac772d68 100644 --- a/voxygen/anim/src/biped_large/alpha.rs +++ b/voxygen/anim/src/biped_large/alpha.rs @@ -63,7 +63,8 @@ impl Animation for AlphaAnimation { let pullback = 1.0 - move3; let move1 = move1base * pullback; let move2 = move2base * pullback; - + next.second.position = Vec3::new(0.0, 0.0, 0.0); + next.second.orientation = Quaternion::rotation_x(0.0); next.shoulder_l.position = Vec3::new( -s_a.shoulder.0, s_a.shoulder.1, @@ -79,7 +80,6 @@ impl Animation for AlphaAnimation { ); next.shoulder_r.orientation = Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm); - next.torso.orientation = Quaternion::rotation_z(0.0); next.main.position = Vec3::new(0.0, 0.0, 0.0); next.main.orientation = Quaternion::rotation_x(0.0); @@ -231,6 +231,38 @@ impl Animation for AlphaAnimation { * Quaternion::rotation_z(move1 * -0.5 + move2 * 0.6); next.head.orientation = Quaternion::rotation_x(move1 * 0.3); }, + "Minotaur" => { + next.control_l.position = Vec3::new(0.0, 4.0, 5.0); + next.control_r.position = Vec3::new(0.0, 4.0, 5.0); + next.weapon_l.position = Vec3::new( + -12.0 + move1 * -9.0 + move2 * 16.0, + -6.0 + move2 * 8.0, + -18.0 + move1 * 8.0 + move2 * -4.0, + ); + next.weapon_r.position = Vec3::new( + 12.0 + move1 * 9.0 + move2 * -16.0, + -6.0 + move2 * 8.0, + -18.0 + move1 * 8.0 + move2 * -8.0, + ); + + next.weapon_l.orientation = Quaternion::rotation_x(-1.67) + * Quaternion::rotation_y(move1 * -0.3 + move2 * 1.0) + * Quaternion::rotation_z(move1 * 0.8 + move2 * -1.8); + next.weapon_r.orientation = Quaternion::rotation_x(-1.67) + * Quaternion::rotation_y(move1 * 0.3 + move2 * -0.6) + * Quaternion::rotation_z(move1 * -0.8 + move2 * 1.8); + + next.control_l.orientation = Quaternion::rotation_x(1.57 + move2 * 1.0); + next.control_r.orientation = Quaternion::rotation_x(1.57 + move2 * 1.0); + + next.shoulder_l.orientation = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(move1 * 0.7 + move2 * -0.7); + + next.shoulder_r.orientation = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(move1 * -0.7 + move2 * 0.7); + next.head.orientation = + Quaternion::rotation_x(move1 * -0.6 + move2 * 0.4) + }, _ => {}, } } diff --git a/voxygen/anim/src/biped_large/chargemelee.rs b/voxygen/anim/src/biped_large/chargemelee.rs new file mode 100644 index 0000000000..0a0862de8a --- /dev/null +++ b/voxygen/anim/src/biped_large/chargemelee.rs @@ -0,0 +1,159 @@ +use super::{ + super::{vek::*, Animation}, + BipedLargeSkeleton, SkeletonAttr, +}; +use common::{ + comp::item::tool::{AbilitySpec, ToolKind}, + states::utils::StageSection, +}; +use std::f32::consts::PI; + +pub struct ChargeMeleeAnimation; + +impl Animation for ChargeMeleeAnimation { + #[allow(clippy::type_complexity)] + type Dependency<'a> = ( + (Option, Option<&'a AbilitySpec>), + (Option, Option<&'a AbilitySpec>), + Vec3, + f32, + Option, + f32, + ); + type Skeleton = BipedLargeSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"biped_large_chargemelee\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "biped_large_chargemelee")] + #[allow(clippy::approx_constant)] // TODO: Pending review in #587 + fn update_skeleton_inner<'a>( + skeleton: &Self::Skeleton, + ( + (active_tool_kind, active_tool_spec), + _second_tool, + velocity, + _global_time, + stage_section, + acc_vel, + ): Self::Dependency<'a>, + anim_time: f32, + rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + *rate = 1.0; + let mut next = (*skeleton).clone(); + let speed = Vec2::::from(velocity).magnitude(); + + let lab: f32 = 0.65 * s_a.tempo; + let speednorm = (speed / 12.0).powf(0.4); + let foothoril = (acc_vel * lab + PI * 1.45).sin() * speednorm; + let foothorir = (acc_vel * lab + PI * (0.45)).sin() * speednorm; + let footrotl = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 1.4).sin()).powi(2))).sqrt()) + * ((acc_vel * lab + PI * 1.4).sin()); + + let footrotr = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 0.4).sin()).powi(2))).sqrt()) + * ((acc_vel * lab + PI * 0.4).sin()); + let (move1base, move2base, movement3, tension) = match stage_section { + Some(StageSection::Charge) => ( + (anim_time.powf(0.25)).min(1.0), + 0.0, + 0.0, + (anim_time * 100.0).sin(), + ), + Some(StageSection::Swing) => (1.0, anim_time.powf(0.25), 0.0, 0.0), + Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4), 0.0), + _ => (0.0, 0.0, 0.0, 0.0), + }; + + let pullback = 1.0 - movement3; + let move1 = move1base * pullback; + let move2 = move2base * pullback; + next.second.position = Vec3::new(0.0, 0.0, 0.0); + next.second.orientation = Quaternion::rotation_x(0.0); + next.shoulder_l.position = Vec3::new( + -s_a.shoulder.0, + s_a.shoulder.1, + s_a.shoulder.2 - foothorir * 1.0, + ); + next.shoulder_l.orientation = + Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotr * -0.2) * speednorm); + + next.shoulder_r.position = Vec3::new( + s_a.shoulder.0, + s_a.shoulder.1, + s_a.shoulder.2 - foothoril * 1.0, + ); + next.shoulder_r.orientation = + Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm); + next.torso.orientation = Quaternion::rotation_z(0.0); + + next.main.position = Vec3::new(0.0, 0.0, 0.0); + next.main.orientation = Quaternion::rotation_x(0.0); + + next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0); + next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0); + + next.hand_l.orientation = Quaternion::rotation_x(0.0); + next.hand_r.orientation = Quaternion::rotation_x(0.0); + + #[allow(clippy::single_match)] + match active_tool_kind { + Some(ToolKind::Natural) => { + if let Some(AbilitySpec::Custom(spec)) = active_tool_spec { + match spec.as_str() { + "Minotaur" => { + next.upper_torso.orientation = + Quaternion::rotation_x(move1 * 0.3 + move2 * -0.9); + next.lower_torso.orientation = + Quaternion::rotation_x(move1 * -0.3 + move2 * 0.9); + next.head.orientation = + Quaternion::rotation_x(move1 * -0.5 + move2 * 0.5); + + next.control_l.position = Vec3::new(0.0, 4.0, 5.0); + next.control_r.position = Vec3::new(0.0, 4.0, 5.0); + next.weapon_l.position = Vec3::new( + -12.0 + move2 * 5.0, + -6.0 + move1 * 22.0 + move2 * 8.0, + -18.0 + move1 * 16.0 + move2 * -19.0, + ); + next.weapon_r.position = Vec3::new( + 12.0 + move2 * -5.0, + -6.0 + move1 * 22.0 + move2 * 8.0, + -18.0 + move1 * 14.0 + move2 * -19.0, + ); + next.torso.position = Vec3::new(0.0, move2 * 1.5, 0.0); + + next.weapon_l.orientation = + Quaternion::rotation_x( + -1.67 + move1 * 2.8 + tension * 0.03 + move2 * -2.3, + ) * Quaternion::rotation_y(move1 * 0.3 + move2 * 0.5); + next.weapon_r.orientation = Quaternion::rotation_x( + -1.67 + move1 * 1.6 + tension * -0.03 + move2 * -0.7, + ) * Quaternion::rotation_y( + move1 * -0.3 + move2 * -0.5, + ) * Quaternion::rotation_z(0.0); + + next.control_l.orientation = + Quaternion::rotation_x(1.57 + move1 * 0.2 + move2 * 0.1); + next.control_r.orientation = + Quaternion::rotation_x(1.57 + move1 * 0.4 + move2 * -0.4); + + next.control.orientation = + Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0); + next.shoulder_l.orientation = + Quaternion::rotation_x(-0.3 + move1 * 1.0); + + next.shoulder_r.orientation = + Quaternion::rotation_x(-0.3 + move1 * 1.0); + }, + _ => {}, + } + } + }, + _ => {}, + } + + next + } +} diff --git a/voxygen/anim/src/biped_large/dash.rs b/voxygen/anim/src/biped_large/dash.rs index 8257b9d075..f969de6df9 100644 --- a/voxygen/anim/src/biped_large/dash.rs +++ b/voxygen/anim/src/biped_large/dash.rs @@ -2,15 +2,19 @@ use super::{ super::{vek::*, Animation}, BipedLargeSkeleton, SkeletonAttr, }; -use common::{comp::item::ToolKind, states::utils::StageSection}; +use common::{ + comp::item::tool::{AbilitySpec, ToolKind}, + states::utils::StageSection, +}; use std::f32::consts::PI; pub struct DashAnimation; impl Animation for DashAnimation { + #[allow(clippy::type_complexity)] type Dependency<'a> = ( - Option, - Option, + (Option, Option<&'a AbilitySpec>), + (Option, Option<&'a AbilitySpec>), Vec3, f32, Option, @@ -25,7 +29,14 @@ impl Animation for DashAnimation { #[allow(clippy::single_match)] // TODO: Pending review in #587 fn update_skeleton_inner<'a>( skeleton: &Self::Skeleton, - (active_tool_kind, _second_tool_kind, velocity, _global_time, stage_section, acc_vel): Self::Dependency<'a>, + ( + (active_tool_kind, active_tool_spec), + _second_tool, + velocity, + _global_time, + stage_section, + acc_vel, + ): Self::Dependency<'a>, anim_time: f32, rate: &mut f32, s_a: &SkeletonAttr, @@ -49,7 +60,8 @@ impl Animation for DashAnimation { next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0); next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0); - + next.second.position = Vec3::new(0.0, 0.0, 0.0); + next.second.orientation = Quaternion::rotation_x(0.0); next.hand_l.orientation = Quaternion::rotation_x(0.0); next.hand_r.orientation = Quaternion::rotation_x(0.0); let (move1base, move2base, move3base, move4) = match stage_section { @@ -136,6 +148,51 @@ impl Animation for DashAnimation { * Quaternion::rotation_y(-1.8 + move1 * -0.2 + move3 * -0.2) * Quaternion::rotation_z(move1 * -0.8 + move3 * -0.1); }, + Some(ToolKind::Natural) => { + if let Some(AbilitySpec::Custom(spec)) = active_tool_spec { + match spec.as_str() { + "Minotaur" => { + next.head.orientation = + Quaternion::rotation_x(move1 * 0.4 + move3 * 0.5) + * Quaternion::rotation_z(move1 * -0.3 + move3 * -0.3); + next.upper_torso.orientation = + Quaternion::rotation_x(move1 * -0.4 + move3 * 0.9) + * Quaternion::rotation_z(move1 * 0.6 + move3 * -1.5); + next.lower_torso.orientation = + Quaternion::rotation_y(move1 * -0.2 + move3 * -0.1) + * Quaternion::rotation_x( + move1 * 0.4 + move3 * -0.7 + footrotr * 0.1, + ) + * Quaternion::rotation_z(move1 * -0.6 + move3 * 1.6); + next.control_l.position = Vec3::new(0.0, 4.0, 5.0); + next.control_r.position = Vec3::new(0.0, 4.0, 5.0); + next.weapon_l.position = Vec3::new(-12.0 + move1 * -3.0, -6.0, -18.0); + next.weapon_r.position = Vec3::new( + 12.0 + move1 * -3.0, + -6.0 + move1 * 2.0, + -18.0 + move1 * 2.0, + ); + + next.weapon_l.orientation = Quaternion::rotation_x(-1.67 + move1 * 0.4) + * Quaternion::rotation_y(move1 * 0.4 + move2 * 0.2) + * Quaternion::rotation_z(move3 * -0.5); + next.weapon_r.orientation = Quaternion::rotation_x(-1.67 + move1 * 0.3) + * Quaternion::rotation_y(move1 * 0.6 + move2 * -0.6) + * Quaternion::rotation_z(move3 * -0.5); + + next.control_l.orientation = Quaternion::rotation_x(1.57); + next.control_r.orientation = Quaternion::rotation_x(1.57); + + next.control.orientation = + Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0); + next.shoulder_l.orientation = Quaternion::rotation_x(-0.3); + + next.shoulder_r.orientation = Quaternion::rotation_x(-0.3); + }, + _ => {}, + } + } + }, _ => {}, } diff --git a/voxygen/anim/src/biped_large/idle.rs b/voxygen/anim/src/biped_large/idle.rs index 62bbf6c87b..92ca199c0c 100644 --- a/voxygen/anim/src/biped_large/idle.rs +++ b/voxygen/anim/src/biped_large/idle.rs @@ -101,8 +101,11 @@ impl Animation for IdleAnimation { next.main.orientation = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57); }, Some(ToolKind::Hammer) | Some(ToolKind::Axe) => { - next.main.position = Vec3::new(-10.0, -8.0, 12.0); + next.main.position = Vec3::new(-6.0, -8.0, 8.0); next.main.orientation = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57); + next.second.position = Vec3::new(6.0, -8.0, 8.0); + next.second.orientation = + Quaternion::rotation_y(-2.5) * Quaternion::rotation_z(1.57); }, _ => { next.main.position = Vec3::new(-2.0, -5.0, -6.0); diff --git a/voxygen/anim/src/biped_large/jump.rs b/voxygen/anim/src/biped_large/jump.rs index e9586d068c..7724daea85 100644 --- a/voxygen/anim/src/biped_large/jump.rs +++ b/voxygen/anim/src/biped_large/jump.rs @@ -28,6 +28,7 @@ impl Animation for JumpAnimation { let torso = (anim_time * lab + 1.5 * PI).sin(); let wave_slow = (anim_time * 0.8).sin(); + next.hold.scale = Vec3::one() * 0.0; next.head.scale = Vec3::one() * 1.02; @@ -57,7 +58,7 @@ impl Animation for JumpAnimation { next.second.position = Vec3::new(0.0, 0.0, 0.0); next.second.orientation = Quaternion::rotation_x(PI) * Quaternion::rotation_y(0.0) * Quaternion::rotation_z(0.0); - next.second.scale = Vec3::one() * 0.0; + next.second.scale = Vec3::one() * 1.0; match active_tool_kind { Some(ToolKind::Bow) => { diff --git a/voxygen/anim/src/biped_large/mod.rs b/voxygen/anim/src/biped_large/mod.rs index 85155ca677..1db51f23b6 100644 --- a/voxygen/anim/src/biped_large/mod.rs +++ b/voxygen/anim/src/biped_large/mod.rs @@ -3,12 +3,14 @@ pub mod beam; pub mod beta; pub mod blink; pub mod charge; +pub mod chargemelee; pub mod dash; pub mod equip; pub mod idle; pub mod jump; pub mod leapmelee; pub mod run; +pub mod selfbuff; pub mod shockwave; pub mod shoot; pub mod spin; @@ -20,11 +22,11 @@ pub mod wield; // Reexports pub use self::{ alpha::AlphaAnimation, beam::BeamAnimation, beta::BetaAnimation, blink::BlinkAnimation, - charge::ChargeAnimation, dash::DashAnimation, equip::EquipAnimation, idle::IdleAnimation, - jump::JumpAnimation, leapmelee::LeapAnimation, run::RunAnimation, - shockwave::ShockwaveAnimation, shoot::ShootAnimation, spin::SpinAnimation, - spinmelee::SpinMeleeAnimation, stunned::StunnedAnimation, summon::SummonAnimation, - wield::WieldAnimation, + charge::ChargeAnimation, chargemelee::ChargeMeleeAnimation, dash::DashAnimation, + equip::EquipAnimation, idle::IdleAnimation, jump::JumpAnimation, leapmelee::LeapAnimation, + run::RunAnimation, selfbuff::SelfBuffAnimation, shockwave::ShockwaveAnimation, + shoot::ShootAnimation, spin::SpinAnimation, spinmelee::SpinMeleeAnimation, + stunned::StunnedAnimation, summon::SummonAnimation, wield::WieldAnimation, }; use super::{make_bone, vek::*, FigureBoneData, Skeleton}; @@ -54,6 +56,8 @@ skeleton_impls!(struct BipedLargeSkeleton { control, control_l, control_r, + weapon_l, + weapon_r, leg_control_l, leg_control_r, arm_control_l, @@ -78,8 +82,11 @@ impl Skeleton for BipedLargeSkeleton { let torso_mat = base_mat * Mat4::::from(self.torso); let upper_torso_mat = torso_mat * upper_torso; + let control_mat = Mat4::::from(self.control); let control_l_mat = Mat4::::from(self.control_l); let control_r_mat = Mat4::::from(self.control_r); + let weapon_l_mat = control_mat * Mat4::::from(self.weapon_l); + let weapon_r_mat = control_mat * Mat4::::from(self.weapon_r); let lower_torso_mat = upper_torso_mat * Mat4::::from(self.lower_torso); let leg_l = Mat4::::from(self.leg_l); @@ -92,8 +99,6 @@ impl Skeleton for BipedLargeSkeleton { let arm_control_r = upper_torso_mat * Mat4::::from(self.arm_control_r); let head_mat = upper_torso_mat * Mat4::::from(self.head); - let control_mat = Mat4::::from(self.control); - let hand_l_mat = Mat4::::from(self.hand_l); *(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [ @@ -102,12 +107,16 @@ impl Skeleton for BipedLargeSkeleton { make_bone(upper_torso_mat), make_bone(lower_torso_mat), make_bone(lower_torso_mat * Mat4::::from(self.tail)), - make_bone(upper_torso_mat * control_mat * Mat4::::from(self.main)), - make_bone(upper_torso_mat * control_mat * Mat4::::from(self.second)), + make_bone(upper_torso_mat * weapon_l_mat * Mat4::::from(self.main)), + make_bone(upper_torso_mat * weapon_r_mat * Mat4::::from(self.second)), make_bone(arm_control_l * Mat4::::from(self.shoulder_l)), make_bone(arm_control_r * Mat4::::from(self.shoulder_r)), - make_bone(arm_control_l * control_mat * control_l_mat * Mat4::::from(self.hand_l)), - make_bone(arm_control_r * control_mat * control_r_mat * Mat4::::from(self.hand_r)), + make_bone( + arm_control_l * weapon_l_mat * control_l_mat * Mat4::::from(self.hand_l), + ), + make_bone( + arm_control_r * weapon_r_mat * control_r_mat * Mat4::::from(self.hand_r), + ), make_bone(leg_control_l * leg_l), make_bone(leg_control_r * leg_r), make_bone(leg_control_l * Mat4::::from(self.foot_l)), diff --git a/voxygen/anim/src/biped_large/run.rs b/voxygen/anim/src/biped_large/run.rs index 2b8a6d67d5..b39791fd20 100644 --- a/voxygen/anim/src/biped_large/run.rs +++ b/voxygen/anim/src/biped_large/run.rs @@ -271,12 +271,12 @@ impl Animation for RunAnimation { s_a.upper_torso.1 + shortalt * -1.5 * speednorm, ); next.upper_torso.orientation = - Quaternion::rotation_z(short * 0.18 * speednorm + tilt * -1.0) + Quaternion::rotation_z(short * 0.07 * speednorm + tilt * -1.0) * Quaternion::rotation_y(tilt); next.lower_torso.position = Vec3::new(0.0, s_a.lower_torso.0, s_a.lower_torso.1); next.lower_torso.orientation = - Quaternion::rotation_z(short * 0.15 * speednorm + tilt * 0.5) + Quaternion::rotation_z(short * 0.05 * speednorm + tilt * 0.5) * Quaternion::rotation_y(tilt * -0.5) * Quaternion::rotation_x(0.14 * speednorm); @@ -287,7 +287,7 @@ impl Animation for RunAnimation { next.tail.orientation = Quaternion::rotation_x(shortalt * 0.3 * speednorm); next.second.position = Vec3::new(0.0, 0.0, 0.0); - next.second.orientation = Quaternion::rotation_x(PI) + next.second.orientation = Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0) * Quaternion::rotation_z(0.0); @@ -308,9 +308,12 @@ impl Animation for RunAnimation { Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57); }, Some(ToolKind::Hammer) | Some(ToolKind::Axe) => { - next.main.position = Vec3::new(-10.0, -8.0, 12.0); + next.main.position = Vec3::new(-6.0, -8.0, 8.0); next.main.orientation = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57); + next.second.position = Vec3::new(6.0, -8.0, 8.0); + next.second.orientation = + Quaternion::rotation_y(-2.5) * Quaternion::rotation_z(1.57); }, _ => { next.main.position = Vec3::new(-2.0, -5.0, -6.0); diff --git a/voxygen/anim/src/biped_large/selfbuff.rs b/voxygen/anim/src/biped_large/selfbuff.rs new file mode 100644 index 0000000000..5b3be3bfe2 --- /dev/null +++ b/voxygen/anim/src/biped_large/selfbuff.rs @@ -0,0 +1,163 @@ +use super::{ + super::{vek::*, Animation}, + BipedLargeSkeleton, SkeletonAttr, +}; +use common::{ + comp::item::tool::{AbilitySpec, ToolKind}, + states::utils::StageSection, +}; +use std::f32::consts::PI; + +pub struct SelfBuffAnimation; + +impl Animation for SelfBuffAnimation { + #[allow(clippy::type_complexity)] + type Dependency<'a> = ( + (Option, Option<&'a AbilitySpec>), + (Option, Option<&'a AbilitySpec>), + Vec3, + f32, + Option, + f32, + ); + type Skeleton = BipedLargeSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"biped_large_selfbuff\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "biped_large_selfbuff")] + #[allow(clippy::approx_constant)] // TODO: Pending review in #587 + fn update_skeleton_inner<'a>( + skeleton: &Self::Skeleton, + ( + (active_tool_kind, active_tool_spec), + _second_tool, + velocity, + _global_time, + stage_section, + acc_vel, + ): Self::Dependency<'a>, + anim_time: f32, + rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + *rate = 1.0; + let mut next = (*skeleton).clone(); + let speed = Vec2::::from(velocity).magnitude(); + + let lab: f32 = 0.65 * s_a.tempo; + let speednorm = (speed / 12.0).powf(0.4); + let foothoril = (acc_vel * lab + PI * 1.45).sin() * speednorm; + let foothorir = (acc_vel * lab + PI * (0.45)).sin() * speednorm; + let footrotl = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 1.4).sin()).powi(2))).sqrt()) + * ((acc_vel * lab + PI * 1.4).sin()); + + let footrotr = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 0.4).sin()).powi(2))).sqrt()) + * ((acc_vel * lab + PI * 0.4).sin()); + let (move1base, movement3, tensionbase, tension2base) = match stage_section { + Some(StageSection::Buildup) => ( + (anim_time.powf(0.25)).min(1.0), + 0.0, + (anim_time * 10.0).sin(), + 0.0, + ), + Some(StageSection::Cast) => { + (1.0, 0.0, (anim_time * 30.0).sin(), (anim_time * 12.0).sin()) + }, + Some(StageSection::Recover) => (1.0, anim_time.powi(4), 1.0, 1.0), + _ => (0.0, 0.0, 0.0, 0.0), + }; + + let pullback = 1.0 - movement3; + let move1 = move1base * pullback; + let tension = tensionbase * pullback; + let tension2 = tension2base * pullback; + + next.second.position = Vec3::new(0.0, 0.0, 0.0); + next.second.orientation = Quaternion::rotation_x(0.0); + next.shoulder_l.position = Vec3::new( + -s_a.shoulder.0, + s_a.shoulder.1, + s_a.shoulder.2 - foothorir * 1.0, + ); + next.shoulder_l.orientation = + Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotr * -0.2) * speednorm); + + next.shoulder_r.position = Vec3::new( + s_a.shoulder.0, + s_a.shoulder.1, + s_a.shoulder.2 - foothoril * 1.0, + ); + next.shoulder_r.orientation = + Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm); + next.torso.orientation = Quaternion::rotation_z(0.0); + + next.main.position = Vec3::new(0.0, 0.0, 0.0); + next.main.orientation = Quaternion::rotation_x(0.0); + + next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0); + next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0); + + next.hand_l.orientation = Quaternion::rotation_x(0.0); + next.hand_r.orientation = Quaternion::rotation_x(0.0); + + #[allow(clippy::single_match)] + match active_tool_kind { + Some(ToolKind::Natural) => { + if let Some(AbilitySpec::Custom(spec)) = active_tool_spec { + match spec.as_str() { + "Minotaur" => { + next.upper_torso.orientation = + Quaternion::rotation_x(move1 * -0.1 + tension2 * 0.05); + next.lower_torso.orientation = + Quaternion::rotation_x(move1 * 0.1 + tension2 * -0.05); + + next.head.orientation = + Quaternion::rotation_x(move1 * 0.8 + tension2 * -0.1) + * Quaternion::rotation_y(tension2 * -0.1); + + next.control_l.position = Vec3::new(0.0, 4.0, 5.0); + next.control_r.position = Vec3::new(0.0, 4.0, 5.0); + next.weapon_l.position = Vec3::new( + -12.0 + move1 * -15.0, + -6.0 + move1 * 13.0, + -18.0 + move1 * 16.0 + tension2 * 3.0, + ); + next.weapon_r.position = Vec3::new( + 12.0 + move1 * 1.0, + -6.0 + move1 * 7.0 + tension * 0.3, + -18.0 + move1 * -2.0, + ); + + next.weapon_l.orientation = Quaternion::rotation_x(-1.67 + move1 * 1.9) + * Quaternion::rotation_y(move1 * 0.25 + tension2 * 0.06) + * Quaternion::rotation_z(move1 * 1.3); + next.weapon_r.orientation = Quaternion::rotation_x(-1.67 + move1 * 0.8) + * Quaternion::rotation_y(move1 * -0.85 + tension * 0.12) + * Quaternion::rotation_z(move1 * 0.7); + + next.control_l.orientation = Quaternion::rotation_x(1.57 + move1 * 0.1) + * Quaternion::rotation_y(0.0); + next.control_r.orientation = Quaternion::rotation_x(1.57 + move1 * 0.1) + * Quaternion::rotation_y(0.0); + + next.control.orientation = + Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0); + next.shoulder_l.orientation = + Quaternion::rotation_x(-0.3 + move1 * 2.2 + tension2 * 0.17) + * Quaternion::rotation_y(move1 * 0.95); + + next.shoulder_r.orientation = + Quaternion::rotation_x(-0.3 + move1 * 0.1) + * Quaternion::rotation_y(move1 * -0.35); + }, + _ => {}, + } + } + }, + _ => {}, + } + + next + } +} diff --git a/voxygen/anim/src/biped_large/stunned.rs b/voxygen/anim/src/biped_large/stunned.rs index cfd429d812..f8f0ff1e53 100644 --- a/voxygen/anim/src/biped_large/stunned.rs +++ b/voxygen/anim/src/biped_large/stunned.rs @@ -65,7 +65,8 @@ impl Animation for StunnedAnimation { let short = (acc_vel * lab).sin() * speednorm; let shortalt = (anim_time * lab * 16.0 + PI / 2.0).sin(); - + next.second.position = Vec3::new(0.0, 0.0, 0.0); + next.second.orientation = Quaternion::rotation_x(0.0); if s_a.beast { next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1); } else { @@ -391,6 +392,24 @@ impl Animation for StunnedAnimation { next.torso.orientation = Quaternion::rotation_x(-0.25); } }, + "Minotaur" => { + next.control_l.position = Vec3::new(0.0, 4.0, 5.0); + next.control_r.position = Vec3::new(0.0, 4.0, 5.0); + next.weapon_l.position = Vec3::new(-12.0, -6.0, -18.0); + next.weapon_r.position = Vec3::new(12.0, -6.0, -18.0); + + next.weapon_l.orientation = Quaternion::rotation_x(-1.57 - 0.1); + next.weapon_r.orientation = Quaternion::rotation_x(-1.57 - 0.1); + + next.control_l.orientation = Quaternion::rotation_x(1.57); + next.control_r.orientation = Quaternion::rotation_x(1.57); + + next.control.orientation = + Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0); + next.shoulder_l.orientation = Quaternion::rotation_x(-0.3); + + next.shoulder_r.orientation = Quaternion::rotation_x(-0.3); + }, _ => {}, } } diff --git a/voxygen/anim/src/biped_large/wield.rs b/voxygen/anim/src/biped_large/wield.rs index f37bf0dc30..6a280feb08 100644 --- a/voxygen/anim/src/biped_large/wield.rs +++ b/voxygen/anim/src/biped_large/wield.rs @@ -91,6 +91,8 @@ impl Animation for WieldAnimation { let short = (acc_vel * lab).sin() * speednorm; let shortalt = (anim_time * lab * 16.0 + PI / 2.0).sin(); + next.second.position = Vec3::new(0.0, 0.0, 0.0); + next.second.orientation = Quaternion::rotation_x(0.0); if s_a.beast { next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1); @@ -169,12 +171,12 @@ impl Animation for WieldAnimation { 5.0 + s_a.grip.0 / 1.2, -4.0 + -s_a.grip.0 / 2.0 + short * -1.5, ); + next.second.scale = Vec3::one() * 0.0; next.control_l.orientation = Quaternion::rotation_x(PI / 2.0) * Quaternion::rotation_y(-0.2); - next.control_r.orientation = Quaternion::rotation_x(PI / 2.2) - * Quaternion::rotation_y(0.2) - * Quaternion::rotation_z(0.0); + next.control_r.orientation = + Quaternion::rotation_x(PI / 2.2) * Quaternion::rotation_y(0.2); next.control.orientation = Quaternion::rotation_x(-0.2 + short * 0.2) * Quaternion::rotation_y(-0.1); @@ -430,6 +432,24 @@ impl Animation for WieldAnimation { next.torso.orientation = Quaternion::rotation_x(-0.25); } }, + "Minotaur" => { + next.control_l.position = Vec3::new(0.0, 4.0, 5.0); + next.control_r.position = Vec3::new(0.0, 4.0, 5.0); + next.weapon_l.position = Vec3::new(-12.0, -6.0, -18.0); + next.weapon_r.position = Vec3::new(12.0, -6.0, -18.0); + + next.weapon_l.orientation = Quaternion::rotation_x(-1.57 - 0.1); + next.weapon_r.orientation = Quaternion::rotation_x(-1.57 - 0.1); + + next.control_l.orientation = Quaternion::rotation_x(1.57); + next.control_r.orientation = Quaternion::rotation_x(1.57); + + next.control.orientation = + Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0); + next.shoulder_l.orientation = Quaternion::rotation_x(-0.3); + + next.shoulder_r.orientation = Quaternion::rotation_x(-0.3); + }, _ => {}, } } diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 1a0dde31f7..754ffd8eec 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -3495,7 +3495,6 @@ struct SidedBLCentralVoxSpec { torso_upper: BipedLargeCentralSubSpec, torso_lower: BipedLargeCentralSubSpec, tail: BipedLargeCentralSubSpec, - second: BipedLargeCentralSubSpec, } #[derive(Deserialize)] struct BipedLargeCentralSubSpec { @@ -3523,13 +3522,16 @@ struct BipedLargeLateralSubSpec { lateral: VoxSimple, } #[derive(Deserialize)] -struct BipedLargeWeaponSpec(HashMap); +struct BipedLargeMainSpec(HashMap); +#[derive(Deserialize)] +struct BipedLargeSecondSpec(HashMap); make_vox_spec!( biped_large::Body, struct BipedLargeSpec { central: BipedLargeCentralSpec = "voxygen.voxel.biped_large_central_manifest", lateral: BipedLargeLateralSpec = "voxygen.voxel.biped_large_lateral_manifest", - weapon: BipedLargeWeaponSpec = "voxygen.voxel.biped_weapon_manifest", + main: BipedLargeMainSpec = "voxygen.voxel.biped_weapon_manifest", + second: BipedLargeSecondSpec = "voxygen.voxel.biped_weapon_manifest", }, |FigureKey { body, extra }, spec| { const DEFAULT_LOADOUT: super::cache::CharacterCacheKey = super::cache::CharacterCacheKey { @@ -3567,15 +3569,17 @@ make_vox_spec!( body.body_type, )), tool.and_then(|tool| tool.active.as_ref()).map(|tool| { - spec.weapon.read().0.mesh_main( + spec.main.read().0.mesh_main( + &tool.name, + false, + ) + }), + tool.and_then(|tool| tool.active.as_ref()).map(|tool| { + spec.second.read().0.mesh_second( &tool.name, false, ) }), - Some(spec.central.read().0.mesh_second( - body.species, - body.body_type, - )), Some(spec.lateral.read().0.mesh_shoulder_l( body.species, body.body_type, @@ -3693,22 +3697,6 @@ impl BipedLargeCentralSpec { (central, Vec3::from(spec.tail.offset)) } - - fn mesh_second(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes { - let spec = match self.0.get(&(species, body_type)) { - Some(spec) => spec, - None => { - error!( - "No second weapon specification exists for the combination of {:?} and {:?}", - species, body_type - ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); - }, - }; - let central = graceful_load_segment(&spec.second.central.0); - - (central, Vec3::from(spec.second.offset)) - } } impl BipedLargeLateralSpec { fn mesh_shoulder_l(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes { @@ -3839,7 +3827,7 @@ impl BipedLargeLateralSpec { (lateral, Vec3::from(spec.foot_r.offset)) } } -impl BipedLargeWeaponSpec { +impl BipedLargeMainSpec { fn mesh_main(&self, item_definition_id: &str, flipped: bool) -> BoneMeshes { let spec = match self.0.get(item_definition_id) { Some(spec) => spec, @@ -3868,6 +3856,35 @@ impl BipedLargeWeaponSpec { (tool_kind_segment, offset) } } +impl BipedLargeSecondSpec { + fn mesh_second(&self, item_definition_id: &str, flipped: bool) -> BoneMeshes { + let spec = match self.0.get(item_definition_id) { + Some(spec) => spec, + None => { + error!(?item_definition_id, "No tool/weapon specification exists"); + return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0)); + }, + }; + + let tool_kind_segment = if flipped { + graceful_load_segment_flipped(&spec.vox_spec.0, true) + } else { + graceful_load_segment(&spec.vox_spec.0) + }; + + let offset = Vec3::new( + if flipped { + 0.0 - spec.vox_spec.1[0] - (tool_kind_segment.sz.x as f32) + } else { + spec.vox_spec.1[0] + }, + spec.vox_spec.1[1], + spec.vox_spec.1[2], + ); + + (tool_kind_segment, offset) + } +} //// #[derive(Deserialize)] struct GolemCentralSpec(HashMap<(GSpecies, GBodyType), SidedGCentralVoxSpec>); diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index c502b07ddf..f0411c9d72 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -3713,7 +3713,84 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::BasicMelee(_) => { + CharacterState::ChargedMelee(s) => { + let stage_time = s.timer.as_secs_f32(); + + let stage_progress = match s.stage_section { + StageSection::Charge => { + stage_time / s.static_data.charge_duration.as_secs_f32() + }, + StageSection::Swing => { + stage_time / s.static_data.swing_duration.as_secs_f32() + }, + StageSection::Recover => { + stage_time / s.static_data.recover_duration.as_secs_f32() + }, + _ => 0.0, + }; + + anim::biped_large::ChargeMeleeAnimation::update_skeleton( + &target_base, + ( + (active_tool_kind, active_tool_spec), + (second_tool_kind, second_tool_spec), + rel_vel, + time, + Some(s.stage_section), + state.acc_vel, + ), + stage_progress, + &mut state_animation_rate, + skeleton_attr, + ) + }, + CharacterState::SelfBuff(s) => { + let stage_time = s.timer.as_secs_f32(); + + let stage_progress = match s.stage_section { + StageSection::Buildup => { + stage_time / s.static_data.buildup_duration.as_secs_f32() + }, + StageSection::Cast => { + stage_time / s.static_data.cast_duration.as_secs_f32() + }, + StageSection::Recover => { + stage_time / s.static_data.recover_duration.as_secs_f32() + }, + _ => 0.0, + }; + + anim::biped_large::SelfBuffAnimation::update_skeleton( + &target_base, + ( + (active_tool_kind, active_tool_spec), + (second_tool_kind, second_tool_spec), + rel_vel, + time, + Some(s.stage_section), + state.acc_vel, + ), + stage_progress, + &mut state_animation_rate, + skeleton_attr, + ) + }, + CharacterState::BasicMelee(s) => { + let stage_time = s.timer.as_secs_f32(); + + let stage_progress = match s.stage_section { + StageSection::Buildup => { + stage_time / s.static_data.buildup_duration.as_secs_f32() + }, + StageSection::Swing => { + stage_time / s.static_data.swing_duration.as_secs_f32() + }, + StageSection::Recover => { + stage_time / s.static_data.recover_duration.as_secs_f32() + }, + _ => 0.0, + }; + anim::biped_large::AlphaAnimation::update_skeleton( &target_base, ( @@ -3721,10 +3798,10 @@ impl FigureMgr { (second_tool_kind, second_tool_spec), rel_vel, time, - None, + Some(s.stage_section), state.acc_vel, ), - state.state_time, + stage_progress, &mut state_animation_rate, skeleton_attr, ) @@ -3875,8 +3952,8 @@ impl FigureMgr { anim::biped_large::DashAnimation::update_skeleton( &target_base, ( - active_tool_kind, - second_tool_kind, + (active_tool_kind, active_tool_spec), + (second_tool_kind, second_tool_spec), rel_vel, time, Some(s.stage_section), From 3aa462ed48882bd12f76830c50ff9f5b4ce5f396 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 27 Apr 2021 21:17:56 -0400 Subject: [PATCH 08/19] Replaced action_timer with action_state so there are additional fields. --- common/src/comp/agent.rs | 9 +- server/src/sys/agent.rs | 211 ++++++++++++++++++++------------------- 2 files changed, 118 insertions(+), 102 deletions(-) diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index 946e937153..a01e5a4e19 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -299,10 +299,17 @@ pub struct Agent { pub behavior: Behavior, pub psyche: Psyche, pub inbox: VecDeque, - pub action_timer: f32, + pub action_state: ActionState, pub bearing: Vec2, } +#[derive(Clone, Debug, Default)] +pub struct ActionState { + pub action_timer: f32, + pub action_float: f32, + pub action_bool: bool, +} + impl Agent { pub fn with_patrol_origin(mut self, origin: Vec3) -> Self { self.patrol_origin = Some(origin); diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index 8ebc872bc7..af774d9e49 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -550,10 +550,10 @@ impl<'a> AgentData<'a> { } // Interact if incoming messages if !agent.inbox.is_empty() { - agent.action_timer = 0.1; + agent.action_state.action_timer = 0.1; } - if agent.action_timer > 0.0 { - if agent.action_timer + if agent.action_state.action_timer > 0.0 { + if agent.action_state.action_timer < (if agent.behavior.is(BehaviorState::TRADING) { TRADE_INTERACTION_TIME } else { @@ -562,7 +562,7 @@ impl<'a> AgentData<'a> { { self.interact(agent, controller, &read_data, event_emitter); } else { - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; agent.target = None; controller.actions.push(ControlAction::Stand); self.idle(agent, controller, &read_data); @@ -582,7 +582,7 @@ impl<'a> AgentData<'a> { event_emitter: &mut Emitter<'_, ServerEvent>, ) { if self.damage < HEALING_ITEM_THRESHOLD && self.heal_self(agent, controller) { - agent.action_timer = 0.01; + agent.action_state.action_timer = 0.01; return; } @@ -596,12 +596,16 @@ impl<'a> AgentData<'a> { let dist_sqrd = self.pos.0.distance_squared(tgt_pos.0); // Should the agent flee? if 1.0 - agent.psyche.aggro > self.damage && self.flees { - if agent.action_timer == 0.0 && agent.behavior.can(BehaviorCapability::SPEAK) { + if agent.action_state.action_timer == 0.0 + && agent.behavior.can(BehaviorCapability::SPEAK) + { let msg = "npc.speech.villager_under_attack".to_string(); event_emitter .emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg))); - agent.action_timer = 0.01; - } else if agent.action_timer < FLEE_DURATION || dist_sqrd < MAX_FLEE_DIST { + agent.action_state.action_timer = 0.01; + } else if agent.action_state.action_timer < FLEE_DURATION + || dist_sqrd < MAX_FLEE_DIST + { self.flee( agent, controller, @@ -610,7 +614,7 @@ impl<'a> AgentData<'a> { &read_data.dt, ); } else { - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; agent.target = None; self.idle(agent, controller, &read_data); } @@ -705,11 +709,11 @@ impl<'a> AgentData<'a> { }; if self.damage < HEALING_ITEM_THRESHOLD && self.heal_self(agent, controller) { - agent.action_timer = 0.01; + agent.action_state.action_timer = 0.01; return; } - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; if let Some((travel_to, _destination)) = &agent.rtsim_controller.travel_to { // if it has an rtsim destination and can fly then it should // if it is flying and bumps something above it then it should move down @@ -901,7 +905,7 @@ impl<'a> AgentData<'a> { // .events // .push(ControlEvent::InviteResponse(InviteResponse::Decline)); // } - agent.action_timer += read_data.dt.0; + agent.action_state.action_timer += read_data.dt.0; let msg = agent.inbox.pop_back(); match msg { Some(AgentEvent::Talk(by, subject)) => { @@ -1250,7 +1254,7 @@ impl<'a> AgentData<'a> { if let Some(Target { target, .. }) = &agent.target { self.look_toward(controller, read_data, target); } else { - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; } } }, @@ -1314,7 +1318,7 @@ impl<'a> AgentData<'a> { self.jump_if(controller, bearing.z > 1.5); controller.inputs.move_z = bearing.z; } - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } /// Attempt to consume a healing item, and return whether any healing items @@ -1379,7 +1383,7 @@ impl<'a> AgentData<'a> { read_data: &ReadData, event_emitter: &mut Emitter<'_, ServerEvent>, ) { - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; // Search area let target = self.cached_spatial_grid.0 @@ -1644,16 +1648,16 @@ impl<'a> AgentData<'a> { Tactic::Axe => { if dist_sqrd < min_attack_dist.powi(2) && angle < 45.0 { controller.inputs.move_dir = Vec2::zero(); - if agent.action_timer > 6.0 { + if agent.action_state.action_timer > 6.0 { controller .actions .push(ControlAction::CancelInput(InputKind::Secondary)); - agent.action_timer = 0.0; - } else if agent.action_timer > 4.0 && self.energy.current() > 10 { + agent.action_state.action_timer = 0.0; + } else if agent.action_state.action_timer > 4.0 && self.energy.current() > 10 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else if self.skill_set.has_skill(Skill::Axe(AxeSkill::UnlockLeap)) && self.energy.current() > 800 && thread_rng().gen_bool(0.5) @@ -1661,12 +1665,12 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -1699,16 +1703,16 @@ impl<'a> AgentData<'a> { Tactic::Hammer => { if dist_sqrd < min_attack_dist.powi(2) && angle < 45.0 { controller.inputs.move_dir = Vec2::zero(); - if agent.action_timer > 4.0 { + if agent.action_state.action_timer > 4.0 { controller .actions .push(ControlAction::CancelInput(InputKind::Secondary)); - agent.action_timer = 0.0; - } else if agent.action_timer > 2.0 { + agent.action_state.action_timer = 0.0; + } else if agent.action_state.action_timer > 2.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else if self .skill_set .has_skill(Skill::Hammer(HammerSkill::UnlockLeap)) @@ -1718,12 +1722,12 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -1742,14 +1746,14 @@ impl<'a> AgentData<'a> { if self .skill_set .has_skill(Skill::Hammer(HammerSkill::UnlockLeap)) - && agent.action_timer > 5.0 + && agent.action_state.action_timer > 5.0 { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; } else { - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } } else { controller.inputs.move_dir = @@ -1776,20 +1780,20 @@ impl<'a> AgentData<'a> { if self .skill_set .has_skill(Skill::Sword(SwordSkill::UnlockSpin)) - && agent.action_timer < 2.0 + && agent.action_state.action_timer < 2.0 && self.energy.current() > 600 { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_timer += dt.0; - } else if agent.action_timer > 2.0 { - agent.action_timer = 0.0; + agent.action_state.action_timer += dt.0; + } else if agent.action_state.action_timer > 2.0 { + agent.action_state.action_timer = 0.0; } else { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -1805,13 +1809,13 @@ impl<'a> AgentData<'a> { if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) { controller.inputs.move_dir = bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed; - if agent.action_timer > 4.0 && angle < 45.0 { + if agent.action_state.action_timer > 4.0 && angle < 45.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; } else { - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } } else { controller.inputs.move_dir = @@ -1886,16 +1890,18 @@ impl<'a> AgentData<'a> { .try_normalized() .unwrap_or_else(Vec2::zero) * speed; - if agent.action_timer > 4.0 { + if agent.action_state.action_timer > 4.0 { controller .actions .push(ControlAction::CancelInput(InputKind::Secondary)); - agent.action_timer = 0.0; - } else if agent.action_timer > 2.0 && self.energy.current() > 300 { + agent.action_state.action_timer = 0.0; + } else if agent.action_state.action_timer > 2.0 + && self.energy.current() > 300 + { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else if self .skill_set .has_skill(Skill::Bow(BowSkill::UnlockRepeater)) @@ -1908,7 +1914,7 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else { controller .actions @@ -1916,7 +1922,7 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } } else { controller.inputs.move_dir = @@ -1961,22 +1967,22 @@ impl<'a> AgentData<'a> { .actions .push(ControlAction::basic_input(InputKind::Roll)); } else if dist_sqrd < (5.0 * min_attack_dist).powi(2) && angle < 15.0 { - if agent.action_timer < 1.5 { + if agent.action_state.action_timer < 1.5 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(0.47 * PI) .try_normalized() .unwrap_or_else(Vec2::unit_y); - agent.action_timer += dt.0; - } else if agent.action_timer < 3.0 { + agent.action_state.action_timer += dt.0; + } else if agent.action_state.action_timer < 3.0 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(-0.47 * PI) .try_normalized() .unwrap_or_else(Vec2::unit_y); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else { - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; } if self .skill_set @@ -2080,13 +2086,13 @@ impl<'a> AgentData<'a> { if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) && angle < 90.0 { controller.inputs.move_dir = bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed; - if agent.action_timer > 5.0 { + if agent.action_state.action_timer > 5.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; } else { - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } } else { controller.inputs.move_dir = @@ -2116,7 +2122,7 @@ impl<'a> AgentData<'a> { } else if dist_sqrd < ((radius as f32 + 1.0) * min_attack_dist).powi(2) && dist_sqrd > (radius as f32 * min_attack_dist).powi(2) { - if agent.action_timer < circle_time as f32 { + if agent.action_state.action_timer < circle_time as f32 { let move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(0.47 * PI) @@ -2133,16 +2139,16 @@ impl<'a> AgentData<'a> { .1 .map_or(true, |b| b.is_some()); if obstacle_left { - agent.action_timer = circle_time as f32; + agent.action_state.action_timer = circle_time as f32; } controller.inputs.move_dir = move_dir; - agent.action_timer += dt.0; - } else if agent.action_timer < circle_time as f32 + 0.5 { + agent.action_state.action_timer += dt.0; + } else if agent.action_state.action_timer < circle_time as f32 + 0.5 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer += dt.0; - } else if agent.action_timer < 2.0 * circle_time as f32 + 0.5 { + agent.action_state.action_timer += dt.0; + } else if agent.action_state.action_timer < 2.0 * circle_time as f32 + 0.5 { let move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(-0.47 * PI) @@ -2159,20 +2165,20 @@ impl<'a> AgentData<'a> { .1 .map_or(true, |b| b.is_some()); if obstacle_right { - agent.action_timer = 2.0 * circle_time as f32 + 0.5; + agent.action_state.action_timer = 2.0 * circle_time as f32 + 0.5; } controller.inputs.move_dir = move_dir; - agent.action_timer += dt.0; - } else if agent.action_timer < 2.0 * circle_time as f32 + 1.0 { - if agent.action_timer < 2.0 * circle_time as f32 { - agent.action_timer = 2.0 * circle_time as f32; + agent.action_state.action_timer += dt.0; + } else if agent.action_state.action_timer < 2.0 * circle_time as f32 + 1.0 { + if agent.action_state.action_timer < 2.0 * circle_time as f32 { + agent.action_state.action_timer = 2.0 * circle_time as f32; } controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else { - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -2215,16 +2221,16 @@ impl<'a> AgentData<'a> { }, ) { if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) && angle < 15.0 { - if agent.action_timer > 5.0 { - agent.action_timer = 0.0; - } else if agent.action_timer > 2.5 { + if agent.action_state.action_timer > 5.0 { + agent.action_state.action_timer = 0.0; + } else if agent.action_state.action_timer > 2.5 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(1.75 * PI) .try_normalized() .unwrap_or_else(Vec2::zero) * speed; - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() @@ -2232,7 +2238,7 @@ impl<'a> AgentData<'a> { .try_normalized() .unwrap_or_else(Vec2::zero) * speed; - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } controller .actions @@ -2254,21 +2260,21 @@ impl<'a> AgentData<'a> { }, Tactic::TailSlap => { if dist_sqrd < (1.5 * min_attack_dist).powi(2) && angle < 90.0 { - if agent.action_timer > 4.0 { + if agent.action_state.action_timer > 4.0 { controller .actions .push(ControlAction::CancelInput(InputKind::Primary)); - agent.action_timer = 0.0; - } else if agent.action_timer > 1.0 { + agent.action_state.action_timer = 0.0; + } else if agent.action_state.action_timer > 1.0 { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() @@ -2336,18 +2342,18 @@ impl<'a> AgentData<'a> { Tactic::QuadLowBasic => { if dist_sqrd < (1.5 * min_attack_dist).powi(2) { controller.inputs.move_dir = Vec2::zero(); - if agent.action_timer > 5.0 { - agent.action_timer = 0.0; - } else if agent.action_timer > 2.0 && angle < 90.0 { + if agent.action_state.action_timer > 5.0 { + agent.action_state.action_timer = 0.0; + } else if agent.action_state.action_timer > 2.0 && angle < 90.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else if angle < 90.0 { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -2410,18 +2416,18 @@ impl<'a> AgentData<'a> { Tactic::QuadMedBasic => { if dist_sqrd < min_attack_dist.powi(2) && angle < 90.0 { controller.inputs.move_dir = Vec2::zero(); - if agent.action_timer < 2.0 { + if agent.action_state.action_timer < 2.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer += dt.0; - } else if agent.action_timer < 3.0 { + agent.action_state.action_timer += dt.0; + } else if agent.action_state.action_timer < 3.0 { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else { - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -2450,7 +2456,7 @@ impl<'a> AgentData<'a> { .actions .push(ControlAction::basic_input(InputKind::Secondary)); } else if dist_sqrd < (7.0 * min_attack_dist).powi(2) && angle < 15.0 { - if agent.action_timer < 2.0 { + if agent.action_state.action_timer < 2.0 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(0.47 * PI) @@ -2459,8 +2465,8 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_timer += dt.0; - } else if agent.action_timer < 4.0 && angle < 15.0 { + agent.action_state.action_timer += dt.0; + } else if agent.action_state.action_timer < 4.0 && angle < 15.0 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(-0.47 * PI) @@ -2469,14 +2475,14 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_timer += dt.0; - } else if agent.action_timer < 6.0 && angle < 15.0 { + agent.action_state.action_timer += dt.0; + } else if agent.action_state.action_timer < 6.0 && angle < 15.0 { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else { - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -2564,20 +2570,20 @@ impl<'a> AgentData<'a> { const MINION_SUMMON_THRESHOLD: f32 = 0.20; let health_fraction = self.health.map_or(0.5, |h| h.fraction()); // Extreme hack to set action_timer at start of combat - if agent.action_timer < MINION_SUMMON_THRESHOLD + if agent.action_state.action_float < MINION_SUMMON_THRESHOLD && health_fraction > MINION_SUMMON_THRESHOLD { - agent.action_timer = health_fraction - MINION_SUMMON_THRESHOLD; + agent.action_state.action_float = 0.8; } let mindflayer_is_far = dist_sqrd > MINDFLAYER_ATTACK_DIST.powi(2); - if agent.action_timer > health_fraction { + if agent.action_state.action_float > health_fraction { // Summon minions at particular thresholds of health controller .actions .push(ControlAction::basic_input(InputKind::Ability(1))); if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover)) { - agent.action_timer -= MINION_SUMMON_THRESHOLD; + agent.action_state.action_float -= MINION_SUMMON_THRESHOLD; } } else if mindflayer_is_far { // If too far from target, blink to them. @@ -2866,18 +2872,21 @@ impl<'a> AgentData<'a> { self.jump_if(controller, bearing.z > 1.5); controller.inputs.move_z = bearing.z; } - } else if self.energy.current() > 600 && agent.action_timer < 3.0 && angle < 15.0 { + } else if self.energy.current() > 600 + && agent.action_state.action_timer < 3.0 + && angle < 15.0 + { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_timer += dt.0; - } else if agent.action_timer < 6.0 && angle < 90.0 { + agent.action_state.action_timer += dt.0; + } else if agent.action_state.action_timer < 6.0 && angle < 90.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_timer += dt.0; + agent.action_state.action_timer += dt.0; } else { - agent.action_timer = 0.0; + agent.action_state.action_timer = 0.0; } }, } From 445af44dfadd6a308f37a28c655f20c0e3a78f20 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 27 Apr 2021 22:33:24 -0400 Subject: [PATCH 09/19] Gave minotaur AI. --- .../abilities/custom/minotaur/cleave.ron | 2 +- common/src/comp/agent.rs | 1 + common/src/states/basic_melee.rs | 1 + common/src/states/dash_melee.rs | 2 + server/src/sys/agent.rs | 78 ++++++++++++++++++- 5 files changed, 80 insertions(+), 4 deletions(-) diff --git a/assets/common/abilities/custom/minotaur/cleave.ron b/assets/common/abilities/custom/minotaur/cleave.ron index f08f594881..19d9c02392 100644 --- a/assets/common/abilities/custom/minotaur/cleave.ron +++ b/assets/common/abilities/custom/minotaur/cleave.ron @@ -10,7 +10,7 @@ ChargedMelee( range: 5.0, max_angle: 45.0, speed: 1.0, - charge_duration: 2.0, + charge_duration: 1.5, swing_duration: 0.1, hit_timing: 0.8, recover_duration: 0.5, diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index a01e5a4e19..9292226dfc 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -40,6 +40,7 @@ pub enum Tactic { Mindflayer, BirdLargeBreathe, BirdLargeFire, + Minotaur, } #[derive(Copy, Clone, Debug, PartialEq)] diff --git a/common/src/states/basic_melee.rs b/common/src/states/basic_melee.rs index 844c3ea2f4..c59d175de5 100644 --- a/common/src/states/basic_melee.rs +++ b/common/src/states/basic_melee.rs @@ -52,6 +52,7 @@ 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.7); handle_jump(data, &mut update, 1.0); handle_orientation(data, &mut update, 0.35); diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index 9e4fe43d9f..1cea70c771 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -76,6 +76,7 @@ impl CharacterBehavior for Data { match self.stage_section { StageSection::Buildup => { if self.timer < self.static_data.buildup_duration { + handle_orientation(data, &mut update, 1.0); // Build up update.character = CharacterState::DashMelee(Data { timer: self @@ -105,6 +106,7 @@ impl CharacterBehavior for Data { / self.static_data.charge_duration.as_secs_f32()) .min(1.0); + handle_orientation(data, &mut update, 0.6); handle_forced_movement( data, &mut update, diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index af774d9e49..89eda2e4d1 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -1542,6 +1542,7 @@ impl<'a> AgentData<'a> { "Bird Large Breathe" => Tactic::BirdLargeBreathe, "Bird Large Fire" => Tactic::BirdLargeFire, "Mindflayer" => Tactic::Mindflayer, + "Minotaur" => Tactic::Minotaur, _ => Tactic::Melee, }, AbilitySpec::Tool(tool_kind) => tool_tactic(*tool_kind), @@ -2569,11 +2570,11 @@ impl<'a> AgentData<'a> { const MINDFLAYER_ATTACK_DIST: f32 = 16.0; const MINION_SUMMON_THRESHOLD: f32 = 0.20; let health_fraction = self.health.map_or(0.5, |h| h.fraction()); - // Extreme hack to set action_timer at start of combat + // Sets action_float at start of combat if agent.action_state.action_float < MINION_SUMMON_THRESHOLD && health_fraction > MINION_SUMMON_THRESHOLD { - agent.action_state.action_float = 0.8; + agent.action_state.action_float = 1.0 - MINION_SUMMON_THRESHOLD; } let mindflayer_is_far = dist_sqrd > MINDFLAYER_ATTACK_DIST.powi(2); if agent.action_state.action_float > health_fraction { @@ -2611,7 +2612,7 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - } else if thread_rng().gen_bool(health_fraction.into()) && angle < 30.0 { + } else if thread_rng().gen_bool(health_fraction.into()) { // Else if at high health, use primary controller .actions @@ -2889,6 +2890,77 @@ impl<'a> AgentData<'a> { agent.action_state.action_timer = 0.0; } }, + Tactic::Minotaur => { + const MINOTAUR_FRENZY_THRESHOLD: f32 = 0.5; + const MINOTAUR_ATTACK_RANGE: f32 = 5.0; + const MINOTAUR_CHARGE_DISTANCE: f32 = 15.0; + let minotaur_attack_distance = + self.body.map_or(0.0, |b| b.radius()) + MINOTAUR_ATTACK_RANGE; + let health_fraction = self.health.map_or(1.0, |h| h.fraction()); + // Sets action float at start of combat + if agent.action_state.action_float < MINOTAUR_FRENZY_THRESHOLD + && health_fraction > MINOTAUR_FRENZY_THRESHOLD + { + agent.action_state.action_float = MINOTAUR_FRENZY_THRESHOLD; + } + if health_fraction < agent.action_state.action_float { + // Makes minotaur buff itself with frenzy + controller + .actions + .push(ControlAction::basic_input(InputKind::Ability(1))); + if matches!(self.char_state, CharacterState::SelfBuff(c) if matches!(c.stage_section, StageSection::Recover)) + { + agent.action_state.action_float = 0.0; + } + } else if matches!(self.char_state, CharacterState::DashMelee(c) if !matches!(c.stage_section, StageSection::Recover)) + { + // If already charging, keep charging if not in recover + controller + .actions + .push(ControlAction::basic_input(InputKind::Ability(0))); + } else if matches!(self.char_state, CharacterState::ChargedMelee(c) if matches!(c.stage_section, StageSection::Charge) && c.timer < c.static_data.charge_duration) + { + // If already charging a melee attack, keep charging it if charging + controller + .actions + .push(ControlAction::basic_input(InputKind::Primary)); + } else if dist_sqrd > MINOTAUR_CHARGE_DISTANCE.powi(2) { + // Charges at target if they are far enough away + if angle < 60.0 { + controller + .actions + .push(ControlAction::basic_input(InputKind::Ability(0))); + } + } else if dist_sqrd < minotaur_attack_distance.powi(2) { + if agent.action_state.action_bool && !self.char_state.is_attack() { + // Cripple target if not just used cripple + controller + .actions + .push(ControlAction::basic_input(InputKind::Secondary)); + agent.action_state.action_bool = false; + } else if !self.char_state.is_attack() { + // Cleave target if not just used cleave + controller + .actions + .push(ControlAction::basic_input(InputKind::Primary)); + agent.action_state.action_bool = true; + } + } + // Make minotaur move towards target + if let Some((bearing, speed)) = agent.chaser.chase( + &*terrain, + self.pos.0, + self.vel.0, + tgt_pos.0, + TraversalConfig { + min_tgt_dist: 1.25, + ..self.traversal_config + }, + ) { + controller.inputs.move_dir = + bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed; + } + }, } } From bb98b021da4a2ec3d3ca8e847180e58ad9d6c021 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 28 Apr 2021 00:23:28 -0400 Subject: [PATCH 10/19] Particles for frenzy buff and ground cleave. --- .../abilities/custom/minotaur/cleave.ron | 1 + assets/voxygen/shaders/particle-vert.glsl | 22 ++++++ common/src/comp/ability.rs | 3 + common/src/outcome.rs | 6 +- common/src/states/charged_melee.rs | 18 +++++ voxygen/src/audio/sfx/mod.rs | 4 ++ voxygen/src/render/pipelines/particle.rs | 2 + voxygen/src/scene/particle.rs | 67 ++++++++++++++++++- 8 files changed, 120 insertions(+), 3 deletions(-) diff --git a/assets/common/abilities/custom/minotaur/cleave.ron b/assets/common/abilities/custom/minotaur/cleave.ron index 19d9c02392..b6b0f88a18 100644 --- a/assets/common/abilities/custom/minotaur/cleave.ron +++ b/assets/common/abilities/custom/minotaur/cleave.ron @@ -14,4 +14,5 @@ ChargedMelee( swing_duration: 0.1, hit_timing: 0.8, recover_duration: 0.5, + specifier: Some(GroundCleave), ) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index dd3ca7b466..d94534313d 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -64,6 +64,8 @@ const int LIFESTEAL_BEAM = 22; const int CULTIST_FLAME = 23; const int STATIC_SMOKE = 24; const int BLOOD = 25; +const int ENRAGED = 26; +const int BIG_SHRAPNEL = 27; // meters per second squared (acceleration) const float earth_gravity = 9.807; @@ -218,6 +220,17 @@ void main() { vec4(vec3(0.25), 1), spin_in_axis(vec3(1,0,0),0) ); + } else if (inst_mode == BIG_SHRAPNEL) { + float brown_color = 0.05 + 0.1 * rand1; + attr = Attr( + linear_motion( + vec3(0), + normalize(vec3(rand4, rand5, rand6)) * 15.0 + grav_vel(earth_gravity) + ), + vec3(5 * (1 - percent())), + vec4(vec3(brown_color, brown_color / 2, 0), 1), + spin_in_axis(vec3(1,0,0),0) + ); } else if (inst_mode == FIREWORK_BLUE) { f_reflect = 0.0; // Fire doesn't reflect light, it emits it attr = Attr( @@ -421,6 +434,15 @@ void main() { vec4(1, 0, 0, 1), spin_in_axis(vec3(1,0,0),0) ); + } else if (inst_mode == ENRAGED) { + f_reflect = 0.0; + float red_color = 1.2 + 0.3 * rand3; + attr = Attr( + (inst_dir * slow_end(1.5)) + vec3(rand0, rand1, rand2) * (percent() + 2) * 0.1, + vec3((3.5 * (1 - slow_start(0.2)))), + vec4(red_color, 0.0, 0.0, 1), + spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9) + ); } else { attr = Attr( linear_motion( diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 9e0525b3e0..37a4da3fe8 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -191,6 +191,7 @@ pub enum CharacterAbility { swing_duration: f32, hit_timing: f32, recover_duration: f32, + specifier: Option, }, ChargedRanged { energy_cost: f32, @@ -1452,6 +1453,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState { recover_duration, range, max_angle, + specifier, } => CharacterState::ChargedMelee(charged_melee::Data { static_data: charged_melee::StaticData { energy_cost: *energy_cost, @@ -1470,6 +1472,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState { hit_timing: *hit_timing, recover_duration: Duration::from_secs_f32(*recover_duration), ability_info, + specifier: *specifier, }, stage_section: StageSection::Charge, timer: Duration::default(), diff --git a/common/src/outcome.rs b/common/src/outcome.rs index afdef6ae47..f4044aa3a4 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -68,6 +68,9 @@ pub enum Outcome { pos: Vec3, state: PoiseState, }, + Bonk { + pos: Vec3, + }, } impl Outcome { @@ -81,7 +84,8 @@ impl Outcome { | Outcome::SummonedCreature { pos, .. } | Outcome::Damage { pos, .. } | Outcome::Block { pos, .. } - | Outcome::PoiseChange { pos, .. } => Some(*pos), + | Outcome::PoiseChange { pos, .. } + | Outcome::Bonk { pos } => Some(*pos), Outcome::BreakBlock { pos, .. } => Some(pos.map(|e| e as f32 + 0.5)), Outcome::ExpChange { .. } | Outcome::ComboChange { .. } => None, } diff --git a/common/src/states/charged_melee.rs b/common/src/states/charged_melee.rs index 30285b964d..6dab18b9d4 100644 --- a/common/src/states/charged_melee.rs +++ b/common/src/states/charged_melee.rs @@ -1,6 +1,8 @@ use crate::{ combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement}, comp::{tool::ToolKind, CharacterState, EnergyChange, EnergySource, Melee, StateUpdate}, + event::LocalEvent, + outcome::Outcome, states::{ behavior::{CharacterBehavior, JoinData}, utils::{StageSection, *}, @@ -45,6 +47,8 @@ pub struct StaticData { pub recover_duration: Duration, /// What key is used to press ability pub ability_info: AbilityInfo, + /// Used to specify the melee attack to the frontend + pub specifier: Option, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -199,6 +203,15 @@ impl CharacterBehavior for Data { }) .filter(|(_, tool)| tool == &Some(ToolKind::Pick)), }); + + // Send local event used for frontend shenanigans + update + .local_events + .push_front(LocalEvent::CreateOutcome(Outcome::Bonk { + pos: data.pos.0 + + *data.ori.look_dir() + * (data.body.radius() + self.static_data.range), + })); } else if self.timer < self.static_data.swing_duration { // Swings update.character = CharacterState::ChargedMelee(Data { @@ -250,3 +263,8 @@ impl CharacterBehavior for Data { update } } + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] +pub enum FrontendSpecifier { + GroundCleave, +} diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 60bf4b4594..40f74c9886 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -325,6 +325,10 @@ impl SfxMgr { false, ); }, + Outcome::Bonk { pos, .. } => { + let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Explosion); + audio.emit_sfx(sfx_trigger_item, *pos, Some(1.0), false); + }, Outcome::ProjectileShot { pos, body, .. } => { match body { Body::Object( diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index 32a73abfde..32b9cebd37 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -122,6 +122,8 @@ pub enum ParticleMode { CultistFlame = 23, StaticSmoke = 24, Blood = 25, + Enraged = 26, + BigShrapnel = 27, } impl ParticleMode { diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 53ae2aea42..813cc4ef4b 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -215,6 +215,16 @@ impl ParticleMgr { }); } }, + Outcome::Bonk { pos, .. } => { + self.particles.resize_with(self.particles.len() + 100, || { + Particle::new( + Duration::from_millis(1000), + time, + ParticleMode::BigShrapnel, + *pos, + ) + }); + }, Outcome::ProjectileShot { .. } | Outcome::Beam { .. } | Outcome::ExpChange { .. } @@ -643,6 +653,36 @@ impl ParticleMgr { }, ); }, + CharacterState::SelfBuff(c) => { + use buff::BuffKind; + if let BuffKind::Frenzied = c.static_data.buff_kind { + if matches!(c.stage_section, StageSection::Cast) { + self.particles.resize_with( + self.particles.len() + + usize::from( + self.scheduler.heartbeats(Duration::from_millis(5)), + ), + || { + let start_pos = pos.0 + + Vec3::new( + body.radius(), + body.radius(), + body.height() / 2.0, + ) + .map(|d| d * rng.gen_range(-1.0..1.0)); + let end_pos = pos.0 + (start_pos - pos.0) * 6.0; + Particle::new_directed( + Duration::from_secs(1), + time, + ParticleMode::Enraged, + start_pos, + end_pos, + ) + }, + ); + } + } + }, _ => {}, } } @@ -818,9 +858,9 @@ impl ParticleMgr { .join() { for (buff_kind, _) in buffs.kinds.iter() { - #[allow(clippy::single_match)] + use buff::BuffKind; match buff_kind { - buff::BuffKind::Cursed | buff::BuffKind::Burning => { + BuffKind::Cursed | BuffKind::Burning => { self.particles.resize_with( self.particles.len() + usize::from(self.scheduler.heartbeats(Duration::from_millis(15))), @@ -850,6 +890,29 @@ impl ParticleMgr { }, ); }, + BuffKind::Frenzied => { + self.particles.resize_with( + self.particles.len() + + usize::from(self.scheduler.heartbeats(Duration::from_millis(15))), + || { + let start_pos = pos.0 + + Vec3::new(body.radius(), body.radius(), body.height() / 2.0) + .map(|d| d * rng.gen_range(-1.0..1.0)); + let end_pos = start_pos + + Vec3::unit_z() * body.height() + + Vec3::::zero() + .map(|_| rng.gen_range(-1.0..1.0)) + .normalized(); + Particle::new_directed( + Duration::from_secs(1), + time, + ParticleMode::Enraged, + start_pos, + end_pos, + ) + }, + ); + }, _ => {}, } } From f49185469935398b3d07e8bf6817e2697024c64b Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 28 Apr 2021 00:32:35 -0400 Subject: [PATCH 11/19] Added kit for testing tier 4 dungeons. --- assets/server/manifests/kits.ron | 16 +++++++++++++++- common/src/states/charged_melee.rs | 18 ++++++++++-------- .../src/audio/sfx/event_mapper/combat/tests.rs | 1 + 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/assets/server/manifests/kits.ron b/assets/server/manifests/kits.ron index dfb76abe25..5032e520a2 100644 --- a/assets/server/manifests/kits.ron +++ b/assets/server/manifests/kits.ron @@ -39,5 +39,19 @@ ("common.items.consumable.potion_med", 100), ("common.items.consumable.potion_big", 100), ("common.items.food.apple_mushroom_curry", 100), - ] + ], + "tier-4": [ + ("common.items.armor.steel.belt", 1), + ("common.items.armor.steel.chest", 1), + ("common.items.armor.steel.foot", 1), + ("common.items.armor.steel.hand", 1), + ("common.items.armor.steel.pants", 1), + ("common.items.armor.steel.shoulder", 1), + ("common.items.weapons.sword.cobalt-0", 1), + ("common.items.weapons.axe.cobalt_axe-0", 1), + ("common.items.weapons.hammer.cobalt_hammer-0", 1), + ("common.items.weapons.bow.frostwood-0", 1), + ("common.items.weapons.staff.frostwood_torch", 1), + ("common.items.weapons.sceptre.fork0", 1), + ], }) diff --git a/common/src/states/charged_melee.rs b/common/src/states/charged_melee.rs index 6dab18b9d4..718220b91b 100644 --- a/common/src/states/charged_melee.rs +++ b/common/src/states/charged_melee.rs @@ -204,14 +204,16 @@ impl CharacterBehavior for Data { .filter(|(_, tool)| tool == &Some(ToolKind::Pick)), }); - // Send local event used for frontend shenanigans - update - .local_events - .push_front(LocalEvent::CreateOutcome(Outcome::Bonk { - pos: data.pos.0 - + *data.ori.look_dir() - * (data.body.radius() + self.static_data.range), - })); + if let Some(FrontendSpecifier::GroundCleave) = self.static_data.specifier { + // Send local event used for frontend shenanigans + update + .local_events + .push_front(LocalEvent::CreateOutcome(Outcome::Bonk { + pos: data.pos.0 + + *data.ori.look_dir() + * (data.body.radius() + self.static_data.range), + })); + } } else if self.timer < self.static_data.swing_duration { // Swings update.character = CharacterState::ChargedMelee(Data { diff --git a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs index 0247bf85c3..35cb0f7c24 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs @@ -79,6 +79,7 @@ fn maps_basic_melee() { range: 1.0, max_angle: 1.0, ability_info: empty_ability_info(), + damage_effect: None, }, timer: Duration::default(), stage_section: states::utils::StageSection::Buildup, From 777eb2ee6a915c841c573e937a32cd63f93dd1b7 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 28 Apr 2021 16:24:03 -0400 Subject: [PATCH 12/19] Balancing. --- assets/common/abilities/custom/minotaur/charge.ron | 4 ++-- assets/common/abilities/custom/minotaur/cleave.ron | 4 ++-- assets/common/abilities/custom/minotaur/cripplingstrike.ron | 2 +- assets/server/manifests/kits.ron | 1 + common/src/comp/body.rs | 3 ++- common/src/comp/buff.rs | 2 +- common/src/states/utils.rs | 2 +- 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/assets/common/abilities/custom/minotaur/charge.ron b/assets/common/abilities/custom/minotaur/charge.ron index 07871af78a..8c85351616 100644 --- a/assets/common/abilities/custom/minotaur/charge.ron +++ b/assets/common/abilities/custom/minotaur/charge.ron @@ -1,7 +1,7 @@ DashMelee( energy_cost: 0, - base_damage: 300, - scaled_damage: 1200, + base_damage: 150, + scaled_damage: 600, base_poise_damage: 25, scaled_poise_damage: 100, base_knockback: 10.0, diff --git a/assets/common/abilities/custom/minotaur/cleave.ron b/assets/common/abilities/custom/minotaur/cleave.ron index b6b0f88a18..5f92519648 100644 --- a/assets/common/abilities/custom/minotaur/cleave.ron +++ b/assets/common/abilities/custom/minotaur/cleave.ron @@ -1,8 +1,8 @@ ChargedMelee( energy_cost: 0, energy_drain: 0, - initial_damage: 200, - scaled_damage: 800, + initial_damage: 0, + scaled_damage: 500, initial_poise_damage: 50, scaled_poise_damage: 150, initial_knockback: 0.0, diff --git a/assets/common/abilities/custom/minotaur/cripplingstrike.ron b/assets/common/abilities/custom/minotaur/cripplingstrike.ron index f363a35a06..7ed3da3469 100644 --- a/assets/common/abilities/custom/minotaur/cripplingstrike.ron +++ b/assets/common/abilities/custom/minotaur/cripplingstrike.ron @@ -3,7 +3,7 @@ BasicMelee( buildup_duration: 0.3, swing_duration: 0.1, recover_duration: 0.6, - base_damage: 250.0, + base_damage: 150.0, base_poise_damage: 60.0, knockback: 15.0, range: 5.0, diff --git a/assets/server/manifests/kits.ron b/assets/server/manifests/kits.ron index 5032e520a2..eeb423c649 100644 --- a/assets/server/manifests/kits.ron +++ b/assets/server/manifests/kits.ron @@ -53,5 +53,6 @@ ("common.items.weapons.bow.frostwood-0", 1), ("common.items.weapons.staff.frostwood_torch", 1), ("common.items.weapons.sceptre.fork0", 1), + ("common.items.consumable.potion_med", 100), ], }) diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index d40719d958..d2d01df77f 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -444,7 +444,7 @@ impl Body { biped_large::Species::Mindflayer => 8000, biped_large::Species::Tidalwarrior => 2500, biped_large::Species::Yeti => 4000, - biped_large::Species::Minotaur => 5000, + biped_large::Species::Minotaur => 30000, biped_large::Species::Harvester => 3000, biped_large::Species::Blueoni => 2400, biped_large::Species::Redoni => 2400, @@ -557,6 +557,7 @@ impl Body { biped_large::Species::Tidalwarrior => 90, biped_large::Species::Yeti => 80, biped_large::Species::Harvester => 80, + biped_large::Species::Minotaur => 0, _ => 100, }, Body::BipedSmall(_) => 10, diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index 131a6af390..287e6a08f8 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -289,7 +289,7 @@ impl Buff { vec![ BuffEffect::MovementSpeed(1.0 + data.strength), BuffEffect::HealthChangeOverTime { - rate: data.strength * 100.0, + rate: data.strength * 500.0, accumulated: 0.0, kind: ModifierKind::Additive, }, diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index e50d70cf81..383f8a4c74 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -71,7 +71,7 @@ impl Body { biped_large::Species::Occultsaurok => 100.0, biped_large::Species::Mightysaurok => 100.0, biped_large::Species::Mindflayer => 90.0, - biped_large::Species::Minotaur => 90.0, + biped_large::Species::Minotaur => 80.0, _ => 80.0, }, Body::BirdMedium(_) => 80.0, From 74a68e24d5c6c8bba6d85cae9cc1f37794662c1e Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 28 Apr 2021 18:41:04 -0400 Subject: [PATCH 13/19] Added sfx. Addressed comments. --- .../custom/minotaur/cripplingstrike.ron | 2 +- assets/voxygen/audio/sfx.ron | 7 + .../audio/sfx/abilities/minotaur_smash_1.ogg | Bin 0 -> 15485 bytes .../audio/sfx/abilities/minotaur_smash_2.ogg | Bin 0 -> 15723 bytes assets/voxygen/i18n/en/buff.ron | 2 +- common/src/comp/agent.rs | 6 +- common/src/comp/buff.rs | 2 +- common/src/outcome.rs | 4 +- common/src/states/charged_melee.rs | 3 +- common/src/states/utils.rs | 2 +- server/src/sys/agent.rs | 218 +++++++++--------- voxygen/src/audio/sfx/mod.rs | 5 +- voxygen/src/scene/particle.rs | 2 +- 13 files changed, 131 insertions(+), 122 deletions(-) create mode 100644 assets/voxygen/audio/sfx/abilities/minotaur_smash_1.ogg create mode 100644 assets/voxygen/audio/sfx/abilities/minotaur_smash_2.ogg diff --git a/assets/common/abilities/custom/minotaur/cripplingstrike.ron b/assets/common/abilities/custom/minotaur/cripplingstrike.ron index 7ed3da3469..f941011081 100644 --- a/assets/common/abilities/custom/minotaur/cripplingstrike.ron +++ b/assets/common/abilities/custom/minotaur/cripplingstrike.ron @@ -7,7 +7,7 @@ BasicMelee( base_poise_damage: 60.0, knockback: 15.0, range: 5.0, - max_angle: 90.0, + max_angle: 60.0, damage_effect: Some(Buff(( kind: Crippled, dur_secs: 15.0, diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index d0ceebf109..bd9434f765 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -824,5 +824,12 @@ ], threshold: 1.25, ), + GroundSlam: ( + files: [ + "voxygen.audio.sfx.abilities.minotaur_smash_1", + "voxygen.audio.sfx.abilities.minotaur_smash_2", + ], + threshold: 0.2, + ), } ) diff --git a/assets/voxygen/audio/sfx/abilities/minotaur_smash_1.ogg b/assets/voxygen/audio/sfx/abilities/minotaur_smash_1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..7ac4e9caee6751fc5f819fb3edc00175d9dd5978 GIT binary patch literal 15485 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 literal 0 HcmV?d00001 diff --git a/assets/voxygen/i18n/en/buff.ron b/assets/voxygen/i18n/en/buff.ron index 6f6047386e..0131214351 100644 --- a/assets/voxygen/i18n/en/buff.ron +++ b/assets/voxygen/i18n/en/buff.ron @@ -20,7 +20,7 @@ "buff.title.protectingward": "Protecting Ward", "buff.desc.protectingward": "You are protected, somewhat, from attacks.", "buff.title.frenzied": "Frenzied", - "buff.desc.frenzied": "You are imbued with nunnatural speed and can ignore minor injuries." + "buff.desc.frenzied": "You are imbued with unnatural speed and can ignore minor injuries.", // Debuffs "buff.title.bleed": "Bleeding", "buff.desc.bleed": "Inflicts regular damage.", diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index 9292226dfc..f2334fca5f 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -306,9 +306,9 @@ pub struct Agent { #[derive(Clone, Debug, Default)] pub struct ActionState { - pub action_timer: f32, - pub action_float: f32, - pub action_bool: bool, + pub timer: f32, + pub counter: f32, + pub condition: bool, } impl Agent { diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index 287e6a08f8..131a6af390 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -289,7 +289,7 @@ impl Buff { vec![ BuffEffect::MovementSpeed(1.0 + data.strength), BuffEffect::HealthChangeOverTime { - rate: data.strength * 500.0, + rate: data.strength * 100.0, accumulated: 0.0, kind: ModifierKind::Additive, }, diff --git a/common/src/outcome.rs b/common/src/outcome.rs index f4044aa3a4..559139d23a 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -68,7 +68,7 @@ pub enum Outcome { pos: Vec3, state: PoiseState, }, - Bonk { + GroundSlam { pos: Vec3, }, } @@ -85,7 +85,7 @@ impl Outcome { | Outcome::Damage { pos, .. } | Outcome::Block { pos, .. } | Outcome::PoiseChange { pos, .. } - | Outcome::Bonk { pos } => Some(*pos), + | Outcome::GroundSlam { pos } => Some(*pos), Outcome::BreakBlock { pos, .. } => Some(pos.map(|e| e as f32 + 0.5)), Outcome::ExpChange { .. } | Outcome::ComboChange { .. } => None, } diff --git a/common/src/states/charged_melee.rs b/common/src/states/charged_melee.rs index 718220b91b..721da8ce20 100644 --- a/common/src/states/charged_melee.rs +++ b/common/src/states/charged_melee.rs @@ -208,7 +208,7 @@ impl CharacterBehavior for Data { // Send local event used for frontend shenanigans update .local_events - .push_front(LocalEvent::CreateOutcome(Outcome::Bonk { + .push_front(LocalEvent::CreateOutcome(Outcome::GroundSlam { pos: data.pos.0 + *data.ori.look_dir() * (data.body.radius() + self.static_data.range), @@ -266,6 +266,7 @@ impl CharacterBehavior for Data { } } +/// Used to specify a particular effect for frontend purposes #[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum FrontendSpecifier { GroundCleave, diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 383f8a4c74..c65908feac 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -71,7 +71,7 @@ impl Body { biped_large::Species::Occultsaurok => 100.0, biped_large::Species::Mightysaurok => 100.0, biped_large::Species::Mindflayer => 90.0, - biped_large::Species::Minotaur => 80.0, + biped_large::Species::Minotaur => 70.0, _ => 80.0, }, Body::BirdMedium(_) => 80.0, diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index 89eda2e4d1..a490634a49 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -550,10 +550,10 @@ impl<'a> AgentData<'a> { } // Interact if incoming messages if !agent.inbox.is_empty() { - agent.action_state.action_timer = 0.1; + agent.action_state.timer = 0.1; } - if agent.action_state.action_timer > 0.0 { - if agent.action_state.action_timer + if agent.action_state.timer > 0.0 { + if agent.action_state.timer < (if agent.behavior.is(BehaviorState::TRADING) { TRADE_INTERACTION_TIME } else { @@ -562,7 +562,7 @@ impl<'a> AgentData<'a> { { self.interact(agent, controller, &read_data, event_emitter); } else { - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; agent.target = None; controller.actions.push(ControlAction::Stand); self.idle(agent, controller, &read_data); @@ -582,7 +582,7 @@ impl<'a> AgentData<'a> { event_emitter: &mut Emitter<'_, ServerEvent>, ) { if self.damage < HEALING_ITEM_THRESHOLD && self.heal_self(agent, controller) { - agent.action_state.action_timer = 0.01; + agent.action_state.timer = 0.01; return; } @@ -596,14 +596,14 @@ impl<'a> AgentData<'a> { let dist_sqrd = self.pos.0.distance_squared(tgt_pos.0); // Should the agent flee? if 1.0 - agent.psyche.aggro > self.damage && self.flees { - if agent.action_state.action_timer == 0.0 + if agent.action_state.timer == 0.0 && agent.behavior.can(BehaviorCapability::SPEAK) { let msg = "npc.speech.villager_under_attack".to_string(); event_emitter .emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg))); - agent.action_state.action_timer = 0.01; - } else if agent.action_state.action_timer < FLEE_DURATION + agent.action_state.timer = 0.01; + } else if agent.action_state.timer < FLEE_DURATION || dist_sqrd < MAX_FLEE_DIST { self.flee( @@ -614,7 +614,7 @@ impl<'a> AgentData<'a> { &read_data.dt, ); } else { - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; agent.target = None; self.idle(agent, controller, &read_data); } @@ -709,11 +709,11 @@ impl<'a> AgentData<'a> { }; if self.damage < HEALING_ITEM_THRESHOLD && self.heal_self(agent, controller) { - agent.action_state.action_timer = 0.01; + agent.action_state.timer = 0.01; return; } - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; if let Some((travel_to, _destination)) = &agent.rtsim_controller.travel_to { // if it has an rtsim destination and can fly then it should // if it is flying and bumps something above it then it should move down @@ -905,7 +905,7 @@ impl<'a> AgentData<'a> { // .events // .push(ControlEvent::InviteResponse(InviteResponse::Decline)); // } - agent.action_state.action_timer += read_data.dt.0; + agent.action_state.timer += read_data.dt.0; let msg = agent.inbox.pop_back(); match msg { Some(AgentEvent::Talk(by, subject)) => { @@ -1254,7 +1254,7 @@ impl<'a> AgentData<'a> { if let Some(Target { target, .. }) = &agent.target { self.look_toward(controller, read_data, target); } else { - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; } } }, @@ -1318,7 +1318,7 @@ impl<'a> AgentData<'a> { self.jump_if(controller, bearing.z > 1.5); controller.inputs.move_z = bearing.z; } - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } /// Attempt to consume a healing item, and return whether any healing items @@ -1383,7 +1383,7 @@ impl<'a> AgentData<'a> { read_data: &ReadData, event_emitter: &mut Emitter<'_, ServerEvent>, ) { - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; // Search area let target = self.cached_spatial_grid.0 @@ -1649,16 +1649,16 @@ impl<'a> AgentData<'a> { Tactic::Axe => { if dist_sqrd < min_attack_dist.powi(2) && angle < 45.0 { controller.inputs.move_dir = Vec2::zero(); - if agent.action_state.action_timer > 6.0 { + if agent.action_state.timer > 6.0 { controller .actions .push(ControlAction::CancelInput(InputKind::Secondary)); - agent.action_state.action_timer = 0.0; - } else if agent.action_state.action_timer > 4.0 && self.energy.current() > 10 { + agent.action_state.timer = 0.0; + } else if agent.action_state.timer > 4.0 && self.energy.current() > 10 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else if self.skill_set.has_skill(Skill::Axe(AxeSkill::UnlockLeap)) && self.energy.current() > 800 && thread_rng().gen_bool(0.5) @@ -1666,12 +1666,12 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -1704,16 +1704,16 @@ impl<'a> AgentData<'a> { Tactic::Hammer => { if dist_sqrd < min_attack_dist.powi(2) && angle < 45.0 { controller.inputs.move_dir = Vec2::zero(); - if agent.action_state.action_timer > 4.0 { + if agent.action_state.timer > 4.0 { controller .actions .push(ControlAction::CancelInput(InputKind::Secondary)); - agent.action_state.action_timer = 0.0; - } else if agent.action_state.action_timer > 2.0 { + agent.action_state.timer = 0.0; + } else if agent.action_state.timer > 2.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else if self .skill_set .has_skill(Skill::Hammer(HammerSkill::UnlockLeap)) @@ -1723,12 +1723,12 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -1747,14 +1747,14 @@ impl<'a> AgentData<'a> { if self .skill_set .has_skill(Skill::Hammer(HammerSkill::UnlockLeap)) - && agent.action_state.action_timer > 5.0 + && agent.action_state.timer > 5.0 { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; } else { - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } } else { controller.inputs.move_dir = @@ -1781,20 +1781,20 @@ impl<'a> AgentData<'a> { if self .skill_set .has_skill(Skill::Sword(SwordSkill::UnlockSpin)) - && agent.action_state.action_timer < 2.0 + && agent.action_state.timer < 2.0 && self.energy.current() > 600 { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_state.action_timer += dt.0; - } else if agent.action_state.action_timer > 2.0 { - agent.action_state.action_timer = 0.0; + agent.action_state.timer += dt.0; + } else if agent.action_state.timer > 2.0 { + agent.action_state.timer = 0.0; } else { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -1810,13 +1810,13 @@ impl<'a> AgentData<'a> { if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) { controller.inputs.move_dir = bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed; - if agent.action_state.action_timer > 4.0 && angle < 45.0 { + if agent.action_state.timer > 4.0 && angle < 45.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; } else { - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } } else { controller.inputs.move_dir = @@ -1891,18 +1891,18 @@ impl<'a> AgentData<'a> { .try_normalized() .unwrap_or_else(Vec2::zero) * speed; - if agent.action_state.action_timer > 4.0 { + if agent.action_state.timer > 4.0 { controller .actions .push(ControlAction::CancelInput(InputKind::Secondary)); - agent.action_state.action_timer = 0.0; - } else if agent.action_state.action_timer > 2.0 + agent.action_state.timer = 0.0; + } else if agent.action_state.timer > 2.0 && self.energy.current() > 300 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else if self .skill_set .has_skill(Skill::Bow(BowSkill::UnlockRepeater)) @@ -1915,7 +1915,7 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else { controller .actions @@ -1923,7 +1923,7 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } } else { controller.inputs.move_dir = @@ -1968,22 +1968,22 @@ impl<'a> AgentData<'a> { .actions .push(ControlAction::basic_input(InputKind::Roll)); } else if dist_sqrd < (5.0 * min_attack_dist).powi(2) && angle < 15.0 { - if agent.action_state.action_timer < 1.5 { + if agent.action_state.timer < 1.5 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(0.47 * PI) .try_normalized() .unwrap_or_else(Vec2::unit_y); - agent.action_state.action_timer += dt.0; - } else if agent.action_state.action_timer < 3.0 { + agent.action_state.timer += dt.0; + } else if agent.action_state.timer < 3.0 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(-0.47 * PI) .try_normalized() .unwrap_or_else(Vec2::unit_y); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else { - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; } if self .skill_set @@ -2087,13 +2087,13 @@ impl<'a> AgentData<'a> { if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) && angle < 90.0 { controller.inputs.move_dir = bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed; - if agent.action_state.action_timer > 5.0 { + if agent.action_state.timer > 5.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; } else { - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } } else { controller.inputs.move_dir = @@ -2123,7 +2123,7 @@ impl<'a> AgentData<'a> { } else if dist_sqrd < ((radius as f32 + 1.0) * min_attack_dist).powi(2) && dist_sqrd > (radius as f32 * min_attack_dist).powi(2) { - if agent.action_state.action_timer < circle_time as f32 { + if agent.action_state.timer < circle_time as f32 { let move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(0.47 * PI) @@ -2140,16 +2140,16 @@ impl<'a> AgentData<'a> { .1 .map_or(true, |b| b.is_some()); if obstacle_left { - agent.action_state.action_timer = circle_time as f32; + agent.action_state.timer = circle_time as f32; } controller.inputs.move_dir = move_dir; - agent.action_state.action_timer += dt.0; - } else if agent.action_state.action_timer < circle_time as f32 + 0.5 { + agent.action_state.timer += dt.0; + } else if agent.action_state.timer < circle_time as f32 + 0.5 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer += dt.0; - } else if agent.action_state.action_timer < 2.0 * circle_time as f32 + 0.5 { + agent.action_state.timer += dt.0; + } else if agent.action_state.timer < 2.0 * circle_time as f32 + 0.5 { let move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(-0.47 * PI) @@ -2166,20 +2166,20 @@ impl<'a> AgentData<'a> { .1 .map_or(true, |b| b.is_some()); if obstacle_right { - agent.action_state.action_timer = 2.0 * circle_time as f32 + 0.5; + agent.action_state.timer = 2.0 * circle_time as f32 + 0.5; } controller.inputs.move_dir = move_dir; - agent.action_state.action_timer += dt.0; - } else if agent.action_state.action_timer < 2.0 * circle_time as f32 + 1.0 { - if agent.action_state.action_timer < 2.0 * circle_time as f32 { - agent.action_state.action_timer = 2.0 * circle_time as f32; + agent.action_state.timer += dt.0; + } else if agent.action_state.timer < 2.0 * circle_time as f32 + 1.0 { + if agent.action_state.timer < 2.0 * circle_time as f32 { + agent.action_state.timer = 2.0 * circle_time as f32; } controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else { - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -2222,16 +2222,16 @@ impl<'a> AgentData<'a> { }, ) { if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) && angle < 15.0 { - if agent.action_state.action_timer > 5.0 { - agent.action_state.action_timer = 0.0; - } else if agent.action_state.action_timer > 2.5 { + if agent.action_state.timer > 5.0 { + agent.action_state.timer = 0.0; + } else if agent.action_state.timer > 2.5 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(1.75 * PI) .try_normalized() .unwrap_or_else(Vec2::zero) * speed; - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() @@ -2239,7 +2239,7 @@ impl<'a> AgentData<'a> { .try_normalized() .unwrap_or_else(Vec2::zero) * speed; - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } controller .actions @@ -2261,21 +2261,21 @@ impl<'a> AgentData<'a> { }, Tactic::TailSlap => { if dist_sqrd < (1.5 * min_attack_dist).powi(2) && angle < 90.0 { - if agent.action_state.action_timer > 4.0 { + if agent.action_state.timer > 4.0 { controller .actions .push(ControlAction::CancelInput(InputKind::Primary)); - agent.action_state.action_timer = 0.0; - } else if agent.action_state.action_timer > 1.0 { + agent.action_state.timer = 0.0; + } else if agent.action_state.timer > 1.0 { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() @@ -2343,18 +2343,18 @@ impl<'a> AgentData<'a> { Tactic::QuadLowBasic => { if dist_sqrd < (1.5 * min_attack_dist).powi(2) { controller.inputs.move_dir = Vec2::zero(); - if agent.action_state.action_timer > 5.0 { - agent.action_state.action_timer = 0.0; - } else if agent.action_state.action_timer > 2.0 && angle < 90.0 { + if agent.action_state.timer > 5.0 { + agent.action_state.timer = 0.0; + } else if agent.action_state.timer > 2.0 && angle < 90.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else if angle < 90.0 { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -2417,18 +2417,18 @@ impl<'a> AgentData<'a> { Tactic::QuadMedBasic => { if dist_sqrd < min_attack_dist.powi(2) && angle < 90.0 { controller.inputs.move_dir = Vec2::zero(); - if agent.action_state.action_timer < 2.0 { + if agent.action_state.timer < 2.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer += dt.0; - } else if agent.action_state.action_timer < 3.0 { + agent.action_state.timer += dt.0; + } else if agent.action_state.timer < 3.0 { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else { - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -2457,7 +2457,7 @@ impl<'a> AgentData<'a> { .actions .push(ControlAction::basic_input(InputKind::Secondary)); } else if dist_sqrd < (7.0 * min_attack_dist).powi(2) && angle < 15.0 { - if agent.action_state.action_timer < 2.0 { + if agent.action_state.timer < 2.0 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(0.47 * PI) @@ -2466,8 +2466,8 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_state.action_timer += dt.0; - } else if agent.action_state.action_timer < 4.0 && angle < 15.0 { + agent.action_state.timer += dt.0; + } else if agent.action_state.timer < 4.0 && angle < 15.0 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .rotated_z(-0.47 * PI) @@ -2476,14 +2476,14 @@ impl<'a> AgentData<'a> { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_state.action_timer += dt.0; - } else if agent.action_state.action_timer < 6.0 && angle < 15.0 { + agent.action_state.timer += dt.0; + } else if agent.action_state.timer < 6.0 && angle < 15.0 { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else { - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; } } else if dist_sqrd < MAX_CHASE_DIST.powi(2) { if let Some((bearing, speed)) = agent.chaser.chase( @@ -2570,21 +2570,21 @@ impl<'a> AgentData<'a> { const MINDFLAYER_ATTACK_DIST: f32 = 16.0; const MINION_SUMMON_THRESHOLD: f32 = 0.20; let health_fraction = self.health.map_or(0.5, |h| h.fraction()); - // Sets action_float at start of combat - if agent.action_state.action_float < MINION_SUMMON_THRESHOLD + // Sets counter at start of combat + if agent.action_state.counter < MINION_SUMMON_THRESHOLD && health_fraction > MINION_SUMMON_THRESHOLD { - agent.action_state.action_float = 1.0 - MINION_SUMMON_THRESHOLD; + agent.action_state.counter = 1.0 - MINION_SUMMON_THRESHOLD; } let mindflayer_is_far = dist_sqrd > MINDFLAYER_ATTACK_DIST.powi(2); - if agent.action_state.action_float > health_fraction { + if agent.action_state.counter > health_fraction { // Summon minions at particular thresholds of health controller .actions .push(ControlAction::basic_input(InputKind::Ability(1))); if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover)) { - agent.action_state.action_float -= MINION_SUMMON_THRESHOLD; + agent.action_state.counter -= MINION_SUMMON_THRESHOLD; } } else if mindflayer_is_far { // If too far from target, blink to them. @@ -2874,20 +2874,20 @@ impl<'a> AgentData<'a> { controller.inputs.move_z = bearing.z; } } else if self.energy.current() > 600 - && agent.action_state.action_timer < 3.0 + && agent.action_state.timer < 3.0 && angle < 15.0 { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - agent.action_state.action_timer += dt.0; - } else if agent.action_state.action_timer < 6.0 && angle < 90.0 { + agent.action_state.timer += dt.0; + } else if agent.action_state.timer < 6.0 && angle < 90.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_timer += dt.0; + agent.action_state.timer += dt.0; } else { - agent.action_state.action_timer = 0.0; + agent.action_state.timer = 0.0; } }, Tactic::Minotaur => { @@ -2898,19 +2898,19 @@ impl<'a> AgentData<'a> { self.body.map_or(0.0, |b| b.radius()) + MINOTAUR_ATTACK_RANGE; let health_fraction = self.health.map_or(1.0, |h| h.fraction()); // Sets action float at start of combat - if agent.action_state.action_float < MINOTAUR_FRENZY_THRESHOLD + if agent.action_state.counter < MINOTAUR_FRENZY_THRESHOLD && health_fraction > MINOTAUR_FRENZY_THRESHOLD { - agent.action_state.action_float = MINOTAUR_FRENZY_THRESHOLD; + agent.action_state.counter = MINOTAUR_FRENZY_THRESHOLD; } - if health_fraction < agent.action_state.action_float { + if health_fraction < agent.action_state.counter { // Makes minotaur buff itself with frenzy controller .actions .push(ControlAction::basic_input(InputKind::Ability(1))); if matches!(self.char_state, CharacterState::SelfBuff(c) if matches!(c.stage_section, StageSection::Recover)) { - agent.action_state.action_float = 0.0; + agent.action_state.counter = 0.0; } } else if matches!(self.char_state, CharacterState::DashMelee(c) if !matches!(c.stage_section, StageSection::Recover)) { @@ -2932,18 +2932,18 @@ impl<'a> AgentData<'a> { .push(ControlAction::basic_input(InputKind::Ability(0))); } } else if dist_sqrd < minotaur_attack_distance.powi(2) { - if agent.action_state.action_bool && !self.char_state.is_attack() { + if agent.action_state.condition && !self.char_state.is_attack() { // Cripple target if not just used cripple controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - agent.action_state.action_bool = false; + agent.action_state.condition = false; } else if !self.char_state.is_attack() { // Cleave target if not just used cleave controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - agent.action_state.action_bool = true; + agent.action_state.condition = true; } } // Make minotaur move towards target diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 40f74c9886..78f91c532f 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -181,6 +181,7 @@ pub enum SfxEvent { FireShot, FlameThrower, PoiseChange(PoiseState), + GroundSlam, } #[derive(Clone, Debug, PartialEq, Deserialize, Hash, Eq)] @@ -325,8 +326,8 @@ impl SfxMgr { false, ); }, - Outcome::Bonk { pos, .. } => { - let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Explosion); + Outcome::GroundSlam { pos, .. } => { + let sfx_trigger_item = triggers.get_key_value(&SfxEvent::GroundSlam); audio.emit_sfx(sfx_trigger_item, *pos, Some(1.0), false); }, Outcome::ProjectileShot { pos, body, .. } => { diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 813cc4ef4b..fdd166abaf 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -215,7 +215,7 @@ impl ParticleMgr { }); } }, - Outcome::Bonk { pos, .. } => { + Outcome::GroundSlam { pos, .. } => { self.particles.resize_with(self.particles.len() + 100, || { Particle::new( Duration::from_millis(1000), From 36640627d9aef1422bc9975841f3e19c5bf12968 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 28 Apr 2021 18:41:40 -0400 Subject: [PATCH 14/19] Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef5794ef44..d53f415afb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -92,6 +92,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Debug Kit is split to "admin_cosmetics" and "debug" - Potion Kit is renamed to "consumables" and gives potions and mushroom curry - Cultist Kit gives cape, rings and necklace in addition to armour and weapons. +- Reworked minotaur to have unique attacks. ### Removed From 1d3e831268400c5ef611ab73864d35b807e9b5ef Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 1 May 2021 09:36:45 -0400 Subject: [PATCH 15/19] Minor balancing tweaks. --- .../common/abilities/custom/mindflayer/cursedflames.ron | 2 +- .../common/abilities/custom/mindflayer/necroticvortex.ron | 2 +- assets/common/abilities/custom/minotaur/frenzy.ron | 2 +- common/src/comp/buff.rs | 2 +- common/src/states/charged_melee.rs | 8 ++++---- common/src/states/utils.rs | 2 +- server/src/sys/agent.rs | 6 ++---- 7 files changed, 11 insertions(+), 13 deletions(-) diff --git a/assets/common/abilities/custom/mindflayer/cursedflames.ron b/assets/common/abilities/custom/mindflayer/cursedflames.ron index f78afb1eda..4559957598 100644 --- a/assets/common/abilities/custom/mindflayer/cursedflames.ron +++ b/assets/common/abilities/custom/mindflayer/cursedflames.ron @@ -2,7 +2,7 @@ BasicBeam( buildup_duration: 0.40, recover_duration: 0.50, beam_duration: 1.0, - damage: 750, + damage: 500, tick_rate: 0.9, range: 22.0, max_angle: 15.0, diff --git a/assets/common/abilities/custom/mindflayer/necroticvortex.ron b/assets/common/abilities/custom/mindflayer/necroticvortex.ron index acd6664570..82f8416777 100644 --- a/assets/common/abilities/custom/mindflayer/necroticvortex.ron +++ b/assets/common/abilities/custom/mindflayer/necroticvortex.ron @@ -2,7 +2,7 @@ SpinMelee( buildup_duration: 0.5, swing_duration: 0.2, recover_duration: 0.6, - base_damage: 150.0, + base_damage: 100.0, base_poise_damage: 1.0, knockback: ( strength: 7.0, direction: Towards), range: 16.0, diff --git a/assets/common/abilities/custom/minotaur/frenzy.ron b/assets/common/abilities/custom/minotaur/frenzy.ron index 5d905a28ac..160a527abc 100644 --- a/assets/common/abilities/custom/minotaur/frenzy.ron +++ b/assets/common/abilities/custom/minotaur/frenzy.ron @@ -4,6 +4,6 @@ SelfBuff( recover_duration: 0.25, buff_kind: Frenzied, buff_strength: 0.5, - buff_duration: None, + buff_duration: Some(300.0), energy_cost: 0, ) \ No newline at end of file diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index 131a6af390..69fe6cf9fe 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -278,7 +278,7 @@ impl Buff { vec![ BuffEffect::MovementSpeed(1.0 - nn_scaling(data.strength)), BuffEffect::HealthChangeOverTime { - rate: -data.strength * 100.0, + rate: -data.strength * 40.0, accumulated: 0.0, kind: ModifierKind::Additive, }, diff --git a/common/src/states/charged_melee.rs b/common/src/states/charged_melee.rs index 721da8ce20..bb12d5b462 100644 --- a/common/src/states/charged_melee.rs +++ b/common/src/states/charged_melee.rs @@ -206,13 +206,13 @@ impl CharacterBehavior for Data { if let Some(FrontendSpecifier::GroundCleave) = self.static_data.specifier { // Send local event used for frontend shenanigans - update - .local_events - .push_front(LocalEvent::CreateOutcome(Outcome::GroundSlam { + update.local_events.push_front(LocalEvent::CreateOutcome( + Outcome::GroundSlam { pos: data.pos.0 + *data.ori.look_dir() * (data.body.radius() + self.static_data.range), - })); + }, + )); } } else if self.timer < self.static_data.swing_duration { // Swings diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index c65908feac..7b155d1787 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -71,7 +71,7 @@ impl Body { biped_large::Species::Occultsaurok => 100.0, biped_large::Species::Mightysaurok => 100.0, biped_large::Species::Mindflayer => 90.0, - biped_large::Species::Minotaur => 70.0, + biped_large::Species::Minotaur => 60.0, _ => 80.0, }, Body::BirdMedium(_) => 80.0, diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index a490634a49..5097b30cfa 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -603,8 +603,7 @@ impl<'a> AgentData<'a> { event_emitter .emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg))); agent.action_state.timer = 0.01; - } else if agent.action_state.timer < FLEE_DURATION - || dist_sqrd < MAX_FLEE_DIST + } else if agent.action_state.timer < FLEE_DURATION || dist_sqrd < MAX_FLEE_DIST { self.flee( agent, @@ -1896,8 +1895,7 @@ impl<'a> AgentData<'a> { .actions .push(ControlAction::CancelInput(InputKind::Secondary)); agent.action_state.timer = 0.0; - } else if agent.action_state.timer > 2.0 - && self.energy.current() > 300 + } else if agent.action_state.timer > 2.0 && self.energy.current() > 300 { controller .actions From 0831970615e842174c813790c9a8f0546bca6de7 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 3 May 2021 16:29:08 -0400 Subject: [PATCH 16/19] Addressed comments and more testing feedback. --- assets/voxygen/i18n/en/buff.ron | 2 ++ common/src/comp/body.rs | 11 ++++++++--- common/src/comp/buff.rs | 30 ++++++++++++++++-------------- server/src/sys/agent.rs | 5 ++--- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/assets/voxygen/i18n/en/buff.ron b/assets/voxygen/i18n/en/buff.ron index 0131214351..bd1f8dd33d 100644 --- a/assets/voxygen/i18n/en/buff.ron +++ b/assets/voxygen/i18n/en/buff.ron @@ -28,6 +28,8 @@ "buff.desc.cursed": "You are cursed.", "buff.title.burn": "On Fire", "buff.desc.burn": "You are burning alive", + "buff.title.crippled": "Crippled", + "buff.desc.crippled": "Your movement is crippled as your legs are heavily injured.", // Buffs stats "buff.stat.health": "Restores {str_total} Health", "buff.stat.increase_max_stamina": "Raises Maximum Stamina by {strength}", diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index d2d01df77f..2b29a2f480 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -441,7 +441,7 @@ impl Body { biped_large::Species::Wendigo => 2800, biped_large::Species::Troll => 2400, biped_large::Species::Dullahan => 3000, - biped_large::Species::Mindflayer => 8000, + biped_large::Species::Mindflayer => 25000, biped_large::Species::Tidalwarrior => 2500, biped_large::Species::Yeti => 4000, biped_large::Species::Minotaur => 30000, @@ -553,10 +553,11 @@ impl Body { biped_large::Species::Wendigo => 80, biped_large::Species::Troll => 60, biped_large::Species::Dullahan => 120, - biped_large::Species::Mindflayer => 250, biped_large::Species::Tidalwarrior => 90, biped_large::Species::Yeti => 80, biped_large::Species::Harvester => 80, + // Boss enemies have their health set, not adjusted by level. + biped_large::Species::Mindflayer => 0, biped_large::Species::Minotaur => 0, _ => 100, }, @@ -606,7 +607,11 @@ impl Body { pub fn combat_multiplier(&self) -> f32 { match self { Body::Object(_) | Body::Ship(_) => 0.0, - Body::BipedLarge(b) if matches!(b.species, biped_large::Species::Mindflayer) => 4.0, + Body::BipedLarge(b) => match b.species { + biped_large::Species::Mindflayer => 4.8, + biped_large::Species::Minotaur => 3.2, + _ => 1.0, + }, _ => 1.0, } } diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index 69fe6cf9fe..2e938937ed 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -14,22 +14,13 @@ use std::{cmp::Ordering, time::Duration}; /// This is used to determine what effects a buff will have #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, PartialOrd, Ord)] pub enum BuffKind { - /// Does damage to a creature over time - /// Strength should be 10x the DPS of the debuff - Burning, + // Buffs /// Restores health/time for some period /// Strength should be 10x the healing per second Regeneration, /// Restores health/time for some period for consumables /// Strength should be 10x the healing per second Saturation, - /// Lowers health over time for some duration - /// Strength should be 10x the DPS of the debuff - Bleeding, - /// Lower a creature's max health over time - /// Strength only affects the target max health, 0.5 targets 50% of base - /// max, 1.0 targets 100% of base max - Cursed, /// Applied when drinking a potion /// Strength should be 10x the healing per second Potion, @@ -49,14 +40,25 @@ pub enum BuffKind { /// Strength scales the damage reduction non-linearly. 0.5 provides 50% DR, /// 1.0 provides 67% DR ProtectingWard, - /// Reduces movement speed and causes bleeding damage - /// Strength scales the movement speed debuff non-linearly. 0.5 is 50% - /// speed, 1.0 is 33% speed. Bleeding is at 10x the value of the strength. - Crippled, /// Increases movement speed and gives health regeneration /// Strength scales the movement speed linearly. 0.5 is 150% speed, 1.0 is /// 200% speed. Provides regeneration at 10x the value of the strength Frenzied, + // Debuffs + /// Does damage to a creature over time + /// Strength should be 10x the DPS of the debuff + Burning, + /// Lowers health over time for some duration + /// Strength should be 10x the DPS of the debuff + Bleeding, + /// Lower a creature's max health over time + /// Strength only affects the target max health, 0.5 targets 50% of base + /// max, 1.0 targets 100% of base max + Cursed, + /// Reduces movement speed and causes bleeding damage + /// Strength scales the movement speed debuff non-linearly. 0.5 is 50% + /// speed, 1.0 is 33% speed. Bleeding is at 10x the value of the strength. + Crippled, } #[cfg(not(target_arch = "wasm32"))] diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index 5097b30cfa..a6c684646c 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -2569,10 +2569,9 @@ impl<'a> AgentData<'a> { const MINION_SUMMON_THRESHOLD: f32 = 0.20; let health_fraction = self.health.map_or(0.5, |h| h.fraction()); // Sets counter at start of combat - if agent.action_state.counter < MINION_SUMMON_THRESHOLD - && health_fraction > MINION_SUMMON_THRESHOLD - { + if agent.action_state.condition { agent.action_state.counter = 1.0 - MINION_SUMMON_THRESHOLD; + agent.action_state.condition = true; } let mindflayer_is_far = dist_sqrd > MINDFLAYER_ATTACK_DIST.powi(2); if agent.action_state.counter > health_fraction { From f6b364c6449ff8830b640f6d27971ffe41a67156 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 4 May 2021 08:44:47 -0400 Subject: [PATCH 17/19] Buff icons --- assets/voxygen/element/de_buffs/buff_frenzy_0.png | Bin 0 -> 293 bytes .../voxygen/element/de_buffs/debuff_cripple_0.png | Bin 0 -> 272 bytes voxygen/src/hud/img_ids.rs | 2 ++ voxygen/src/hud/mod.rs | 6 ++---- 4 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 assets/voxygen/element/de_buffs/buff_frenzy_0.png create mode 100644 assets/voxygen/element/de_buffs/debuff_cripple_0.png diff --git a/assets/voxygen/element/de_buffs/buff_frenzy_0.png b/assets/voxygen/element/de_buffs/buff_frenzy_0.png new file mode 100644 index 0000000000000000000000000000000000000000..1b8c0e36d2225052e15808857a5bd1b084bed842 GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VTavfC3&Vd9T(EcfWS|IVfk$L9 z1B0G22s2hJwJ!q-9`$r_46!(!oRW}`;NkE8|GWdMLGd#mw_{(veEIJl${%>xhVAw3 zG9Dd+bC*NUOWvDXb6z1u&tsCJf$gQlNjxCn!xO^hb0bIPXlVs+OXYM4=ftcF%^j@) zHx@|u`SPrvzERR^O=1MEit4nDD^rz1nH9MsIVy$cyWY5BG;xwiM`x{A&bG&wJ9OI5 zs_Xnnnj$j&^|!2rRg$w$Z`dg^TPo%B%nzb7C5OWp#K~ g#vL#U+6@c_#=wTetJ>y&fF5G-boFyt=akR{04i~7y8r+H literal 0 HcmV?d00001 diff --git a/assets/voxygen/element/de_buffs/debuff_cripple_0.png b/assets/voxygen/element/de_buffs/debuff_cripple_0.png new file mode 100644 index 0000000000000000000000000000000000000000..21bfad719ac8ac5ece64f6c321cc170c1d17aa80 GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VTavfC3&Vd9T(EcfWS|IVfk$L9 z1B0G22s2hJwJ!q-Zt!$*46!)9cIsZi76pM;c^<{iwJ~|D*9tyfbEz?nIQVp1Qqnuu z7pDq#|Jloucs&1JG@Ai~gNr(wMoR*Z;N114vIh@u(*m3z3s8&pR{$ P-Ok|Y>gTe~DWM4fvhQv# literal 0 HcmV?d00001 diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index b74af470be..2e670e7517 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -569,11 +569,13 @@ image_ids! { buff_healthplus_0: "voxygen.element.de_buffs.buff_healthplus_0", buff_invincibility_0: "voxygen.element.de_buffs.buff_invincibility_0", buff_dmg_red_0: "voxygen.element.de_buffs.buff_damage_reduce_0", + buff_frenzy_0: "voxygen.element.de_buffs.buff_frenzy_0", // Debuffs debuff_skull_0: "voxygen.element.de_buffs.debuff_skull_0", debuff_bleed_0: "voxygen.element.de_buffs.debuff_bleed_0", debuff_burning_0: "voxygen.element.de_buffs.debuff_burning_0", + debuff_crippled_0: "voxygen.element.de_buffs.debuff_cripple_0", // Animation Frames // Buff Frame diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 83ad74a6d5..6ac6c7a17b 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -3622,14 +3622,12 @@ pub fn get_buff_image(buff: BuffKind, imgs: &Imgs) -> conrod_core::image::Id { BuffKind::IncreaseMaxHealth { .. } => imgs.buff_healthplus_0, BuffKind::Invulnerability => imgs.buff_invincibility_0, BuffKind::ProtectingWard => imgs.buff_dmg_red_0, - // TODO: Get buff icon - BuffKind::Frenzied { .. } => imgs.buff_invincibility_0, + BuffKind::Frenzied { .. } => imgs.buff_frenzy_0, // Debuffs BuffKind::Bleeding { .. } => imgs.debuff_bleed_0, BuffKind::Cursed { .. } => imgs.debuff_skull_0, BuffKind::Burning { .. } => imgs.debuff_burning_0, - // TODO: Get buff icon - BuffKind::Crippled { .. } => imgs.debuff_bleed_0, + BuffKind::Crippled { .. } => imgs.debuff_crippled_0, } } From 344e8c8a679580ac77d5a629ecc32e98668893bc Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 4 May 2021 09:22:10 -0400 Subject: [PATCH 18/19] Made buff commands exhaustive --- Cargo.lock | 2 ++ assets/voxygen/i18n/en/hud/chat.ron | 1 + common/Cargo.toml | 6 +++- common/src/cmd.rs | 56 ++++++++++++++++++++--------- common/src/comp/buff.rs | 5 ++- server/src/cmd.rs | 43 +++------------------- voxygen/src/hud/chat.rs | 4 ++- 7 files changed, 60 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5600abfcae..4c86d1e3ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5542,6 +5542,8 @@ dependencies = [ "specs-idvs", "spin_sleep", "structopt", + "strum", + "strum_macros", "tracing", "tracing-subscriber", "uuid", diff --git a/assets/voxygen/i18n/en/hud/chat.ron b/assets/voxygen/i18n/en/hud/chat.ron index 1e46dea342..394db4c2dc 100644 --- a/assets/voxygen/i18n/en/hud/chat.ron +++ b/assets/voxygen/i18n/en/hud/chat.ron @@ -7,6 +7,7 @@ "hud.outcome.burning": "died of: burning", "hud.outcome.curse": "died of: curse", "hud.outcome.bleeding": "died of: bleeding", + "hud.outcome.crippled": "died of: crippled", // Chat outputs "hud.chat.online_msg": "[{name}] is online now", diff --git a/common/Cargo.toml b/common/Cargo.toml index 533a966a6f..2d8f2ed24e 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -49,7 +49,7 @@ ron = { version = "0.6", default-features = false } serde_json = "1.0.50" serde_repr = "0.1.6" -# esv export +# csv export csv = { version = "1.1.3", optional = true } structopt = { version = "0.3.13", optional = true } @@ -59,6 +59,10 @@ slotmap = { version = "1.0", features = ["serde"] } indexmap = "1.3.0" slab = "0.4.2" +# Strum +strum = "0.20" +strum_macros = "0.20" + # ECS specs = { git = "https://github.com/amethyst/specs.git", features = ["serde", "storage-event-control", "nightly"], rev = "5a9b71035007be0e3574f35184acac1cd4530496" } specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "b65fb220e94f5d3c9bc30074a076149763795556" } diff --git a/common/src/cmd.rs b/common/src/cmd.rs index 008bf3f89d..911f30d32c 100644 --- a/common/src/cmd.rs +++ b/common/src/cmd.rs @@ -1,4 +1,8 @@ -use crate::{assets, comp, npc, terrain}; +use crate::{ + assets, + comp::{self, buff::BuffKind}, + npc, terrain, +}; use assets::AssetExt; use hashbrown::HashMap; use lazy_static::lazy_static; @@ -8,6 +12,7 @@ use std::{ path::Path, str::FromStr, }; +use strum::IntoEnumIterator; use tracing::warn; /// Struct representing a command that a user can run from server chat. @@ -210,21 +215,40 @@ lazy_static! { .map(|s| s.to_string()) .collect(); - static ref BUFFS: Vec = vec![ - // Debuffs - "burning", "bleeding", "curse", - // Heal - "regeneration", "saturation", "potion", "campfire_heal", - // Outmaxing stats - "increase_max_energy", "increase_max_health", - // Defensive buffs - "invulnerability", "protecting_ward", - // One command to rule them all - "all", - ] - .iter() - .map(|b| b.to_string()) - .collect(); + pub static ref BUFF_PARSER: HashMap = { + let string_from_buff = |kind| match kind { + BuffKind::Burning => "burning", + BuffKind::Regeneration => "regeration", + BuffKind::Saturation => "saturation", + BuffKind::Bleeding => "bleeding", + BuffKind::Cursed => "cursed", + BuffKind::Potion => "potion", + BuffKind::CampfireHeal => "campfire_heal", + BuffKind::IncreaseMaxEnergy => "increase_max_energy", + BuffKind::IncreaseMaxHealth => "increase_max_health", + BuffKind::Invulnerability => "invulnerability", + BuffKind::ProtectingWard => "protecting_ward", + BuffKind::Frenzied => "frenzied", + BuffKind::Crippled => "crippled", + }; + let mut buff_parser = HashMap::new(); + BuffKind::iter().for_each(|kind| {buff_parser.insert(string_from_buff(kind).to_string(), kind);}); + buff_parser + }; + + pub static ref BUFF_PACK: Vec = { + let mut buff_pack: Vec<_> = BUFF_PARSER.keys().cloned().collect(); + // Remove invulnerability as it removes debuffs + buff_pack.retain(|kind| kind != "invulnerability"); + buff_pack + }; + + static ref BUFFS: Vec = { + let mut buff_pack: Vec<_> = BUFF_PARSER.keys().cloned().collect(); + // Add all as valid command + buff_pack.push("all".to_string()); + buff_pack + }; static ref BLOCK_KINDS: Vec = terrain::block::BLOCK_KINDS .keys() diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index 2e938937ed..b7bbe5bacb 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -9,10 +9,13 @@ use specs::{Component, DerefFlaggedStorage}; use specs_idvs::IdvStorage; #[cfg(not(target_arch = "wasm32"))] use std::{cmp::Ordering, time::Duration}; +use strum_macros::EnumIter; /// De/buff Kind. /// This is used to determine what effects a buff will have -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, PartialOrd, Ord)] +#[derive( + Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, PartialOrd, Ord, EnumIter, +)] pub enum BuffKind { // Buffs /// Restores health/time for some period diff --git a/server/src/cmd.rs b/server/src/cmd.rs index ec604c7ba8..bf1ecafd1a 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -11,7 +11,7 @@ use authc::Uuid; use chrono::{NaiveTime, Timelike}; use common::{ assets, - cmd::{ChatCommand, CHAT_COMMANDS, CHAT_SHORTCUTS}, + cmd::{ChatCommand, BUFF_PACK, BUFF_PARSER, CHAT_COMMANDS, CHAT_SHORTCUTS}, comp::{ self, aura::{Aura, AuraKind, AuraTarget}, @@ -36,13 +36,11 @@ use common_net::{ }; use common_state::{BuildAreaError, BuildAreas}; use core::{convert::TryFrom, ops::Not, time::Duration}; -use hashbrown::HashSet; +use hashbrown::{HashMap, HashSet}; use rand::Rng; use specs::{Builder, Entity as EcsEntity, Join, WorldExt}; -use wiring::{Circuit, Wire, WiringAction, WiringActionEffect, WiringElement}; - -use hashbrown::HashMap; use vek::*; +use wiring::{Circuit, Wire, WiringAction, WiringActionEffect, WiringElement}; use world::util::Sampler; use crate::{client::Client, login_provider::LoginProvider, wiring}; @@ -2615,22 +2613,6 @@ fn handle_apply_buff( args: String, action: &ChatCommand, ) -> CmdResult<()> { - const BUFF_PACK: &[&str] = &[ - // Debuffs - "burning", - "bleeding", - "curse", - // Healing - "regeneration", - "saturation", - "potion", - "campfire_heal", - // Outmaxing stats - "increase_max_energy", - "increase_max_health", - // Defensive buffs (invulnerability is skipped because it ruins all debuffs) - "protecting_ward", - ]; if let (Some(buff), strength, duration) = scan_fmt_some!(&args, &action.arg_fmt(), String, f32, f64) { @@ -2640,7 +2622,7 @@ fn handle_apply_buff( if buff != "all" { cast_buff(&buff, buffdata, server, target) } else { - for kind in BUFF_PACK { + for kind in BUFF_PACK.iter() { cast_buff(kind, buffdata, server, target)?; } Ok(()) @@ -2663,19 +2645,4 @@ fn cast_buff(kind: &str, data: BuffData, server: &mut Server, target: EcsEntity) } } -fn parse_buffkind(buff: &str) -> Option { - match buff { - "burning" => Some(BuffKind::Burning), - "regeneration" => Some(BuffKind::Regeneration), - "saturation" => Some(BuffKind::Saturation), - "bleeding" => Some(BuffKind::Bleeding), - "curse" => Some(BuffKind::Cursed), - "potion" => Some(BuffKind::Potion), - "campfire_heal" => Some(BuffKind::CampfireHeal), - "increase_max_energy" => Some(BuffKind::IncreaseMaxEnergy), - "increase_max_health" => Some(BuffKind::IncreaseMaxHealth), - "invulnerability" => Some(BuffKind::Invulnerability), - "protecting_ward" => Some(BuffKind::ProtectingWard), - _ => None, - } -} +fn parse_buffkind(buff: &str) -> Option { BUFF_PARSER.get(buff).copied() } diff --git a/voxygen/src/hud/chat.rs b/voxygen/src/hud/chat.rs index f91a5a0182..0795e3c930 100644 --- a/voxygen/src/hud/chat.rs +++ b/voxygen/src/hud/chat.rs @@ -628,6 +628,7 @@ fn insert_killing_buff(buff: BuffKind, localized_strings: &Localization, templat BuffKind::Burning => localized_strings.get("hud.outcome.burning"), BuffKind::Bleeding => localized_strings.get("hud.outcome.bleeding"), BuffKind::Cursed => localized_strings.get("hud.outcome.curse"), + BuffKind::Crippled => localized_strings.get("hud.outcome.crippled"), BuffKind::Regeneration | BuffKind::Saturation | BuffKind::Potion @@ -635,7 +636,8 @@ fn insert_killing_buff(buff: BuffKind, localized_strings: &Localization, templat | BuffKind::IncreaseMaxEnergy | BuffKind::IncreaseMaxHealth | BuffKind::Invulnerability - | BuffKind::ProtectingWard => { + | BuffKind::ProtectingWard + | BuffKind::Frenzied => { tracing::error!("Player was killed by a positive buff!"); localized_strings.get("hud.outcome.mysterious") }, From ccb5a80a88c3f9ff95e47076a01f9f9a247f2e82 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 4 May 2021 11:27:17 -0400 Subject: [PATCH 19/19] Removed useless clippy allow, added todo. --- voxygen/anim/src/biped_large/selfbuff.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voxygen/anim/src/biped_large/selfbuff.rs b/voxygen/anim/src/biped_large/selfbuff.rs index 5b3be3bfe2..059e4481e6 100644 --- a/voxygen/anim/src/biped_large/selfbuff.rs +++ b/voxygen/anim/src/biped_large/selfbuff.rs @@ -26,7 +26,6 @@ impl Animation for SelfBuffAnimation { const UPDATE_FN: &'static [u8] = b"biped_large_selfbuff\0"; #[cfg_attr(feature = "be-dyn-lib", export_name = "biped_large_selfbuff")] - #[allow(clippy::approx_constant)] // TODO: Pending review in #587 fn update_skeleton_inner<'a>( skeleton: &Self::Skeleton, ( @@ -101,6 +100,7 @@ impl Animation for SelfBuffAnimation { next.hand_l.orientation = Quaternion::rotation_x(0.0); next.hand_r.orientation = Quaternion::rotation_x(0.0); + // TODO: Remove clippy allow when second species is added #[allow(clippy::single_match)] match active_tool_kind { Some(ToolKind::Natural) => {