From e62c0cd1bd8ba0350ea8e6592951aeb40e22da20 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 27 Aug 2020 21:13:57 -0500 Subject: [PATCH] Lifesteal now works. Added particles to healing beam. --- assets/voxygen/shaders/particle-vert.glsl | 8 ++++++ common/src/comp/ability.rs | 2 ++ common/src/comp/inventory/item/tool.rs | 4 +-- common/src/states/basic_beam.rs | 22 +++++++++------ common/src/sys/combat.rs | 12 ++++++-- voxygen/src/render/pipelines/particle.rs | 1 + voxygen/src/scene/particle.rs | 34 +++++++++++++++++++++++ 7 files changed, 70 insertions(+), 13 deletions(-) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index c22cf9a264..132437d43b 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -48,6 +48,7 @@ const int LEAF = 9; const int FIREFLY = 10; const int BEE = 11; const int GROUND_SHOCKWAVE = 12; +const int HEALING_BEAM = 13; // meters per second squared (acceleration) const float earth_gravity = 9.807; @@ -248,6 +249,13 @@ void main() { vec4(vec3(0.32 + (rand0 * 0.04), 0.22 + (rand1 * 0.03), 0.05 + (rand2 * 0.01)), 1), spin_in_axis(vec3(1,0,0),0) ); + } else if (inst_mode == HEALING_BEAM) { + attr = Attr( + vec3(rand0 * 0.2, rand1 * 0.2, rand2 * 0.2 + 1), + 1, + vec4(vec3(0, 1, 0), 1), + spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5) + ); } else { attr = Attr( linear_motion( diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 9da47c0bb5..edd000565f 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize}; use specs::{Component, FlaggedStorage}; use specs_idvs::IdvStorage; use std::time::Duration; +use vek::Vec3; #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Serialize, Deserialize)] pub enum CharacterAbilityType { @@ -526,6 +527,7 @@ impl From<&CharacterAbility> for CharacterState { energy_regen, } => CharacterState::BasicBeam(basic_beam::Data { exhausted: false, + particle_ori: None::>, buildup_duration: *buildup_duration, cooldown_duration: Duration::from_millis(250), cooldown_duration_default: Duration::from_millis(250), diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index c98e0365c5..260c1a5caf 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -310,8 +310,8 @@ impl Tool { base_dps: (80.0 * self.base_power()) as u32, range: 25.0, max_angle: 1.0, - lifesteal_eff: 0.2, - energy_regen: 50, + lifesteal_eff: 0.25, + energy_regen: 120, }, BasicMelee { energy_cost: 350, diff --git a/common/src/states/basic_beam.rs b/common/src/states/basic_beam.rs index cd6787b7cc..e8651d5f2d 100644 --- a/common/src/states/basic_beam.rs +++ b/common/src/states/basic_beam.rs @@ -5,11 +5,14 @@ use crate::{ }; use serde::{Deserialize, Serialize}; use std::time::Duration; +use vek::Vec3; #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Data { /// Whether the attack can currently deal damage pub exhausted: bool, + /// Used for particle stuffs + pub particle_ori: Option>, /// How long until state should deal damage or heal pub buildup_duration: Duration, /// How long until weapon can deal another tick of damage @@ -46,6 +49,7 @@ impl CharacterBehavior for Data { // Build up update.character = CharacterState::BasicBeam(Data { exhausted: self.exhausted, + particle_ori: Some(*data.inputs.look_dir), buildup_duration: self .buildup_duration .checked_sub(Duration::from_secs_f32(data.dt.0)) @@ -73,11 +77,12 @@ impl CharacterBehavior for Data { hit_count: 0, knockback: 0.0, is_melee: false, - lifesteal_eff: 0.0, + lifesteal_eff: self.lifesteal_eff, }); update.character = CharacterState::BasicBeam(Data { exhausted: true, + particle_ori: Some(*data.inputs.look_dir), buildup_duration: self.buildup_duration, recover_duration: self.recover_duration, cooldown_duration: self.cooldown_duration_default, @@ -89,18 +94,11 @@ impl CharacterBehavior for Data { lifesteal_eff: self.lifesteal_eff, energy_regen: self.energy_regen, }); - - // Grant energy and lifesteal on successful hit - if let Some(attack) = data.attacking { - if attack.applied && attack.hit_count > 0 { - let energy = (self.energy_regen as f32 / ticks_per_sec) as i32; - update.energy.change_by(energy, EnergySource::HitEnemy); - } - } } else if data.inputs.primary.is_pressed() && self.cooldown_duration != Duration::default() { // Cooldown until next tick of damage update.character = CharacterState::BasicBeam(Data { exhausted: self.exhausted, + particle_ori: Some(*data.inputs.look_dir), buildup_duration: self.buildup_duration, cooldown_duration: self .cooldown_duration @@ -118,6 +116,7 @@ impl CharacterBehavior for Data { } else if data.inputs.primary.is_pressed() { update.character = CharacterState::BasicBeam(Data { exhausted: false, + particle_ori: Some(*data.inputs.look_dir), buildup_duration: self.buildup_duration, recover_duration: self.recover_duration, cooldown_duration: self.cooldown_duration_default, @@ -129,10 +128,15 @@ impl CharacterBehavior for Data { lifesteal_eff: self.lifesteal_eff, energy_regen: self.energy_regen, }); + + // Grant energy on successful hit + let energy = (self.energy_regen as f32 / ticks_per_sec) as i32; + update.energy.change_by(energy, EnergySource::HitEnemy); } else if self.recover_duration != Duration::default() { // Recovery update.character = CharacterState::BasicBeam(Data { exhausted: self.exhausted, + particle_ori: Some(*data.inputs.look_dir), buildup_duration: self.buildup_duration, cooldown_duration: self.cooldown_duration, cooldown_duration_default: self.cooldown_duration_default, diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index fec783a3ad..9cb1a4c4d7 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -120,6 +120,9 @@ impl<'a> System<'a> for Sys { if same_group && (attack.base_heal > 0) { is_heal = true; } + if !is_heal && !is_damage { + continue; + } // Weapon gives base damage let source = if is_heal { @@ -129,8 +132,13 @@ impl<'a> System<'a> for Sys { } else { DamageSource::Energy }; + let healthchange = if is_heal { + attack.base_heal as f32 + } else { + -(attack.base_damage as f32) + }; let mut damage = Damage { - healthchange: -(attack.base_damage as f32), + healthchange, source, }; @@ -150,7 +158,7 @@ impl<'a> System<'a> for Sys { cause, }, }); - if attack.lifesteal_eff != 0.0 && is_damage { + if attack.lifesteal_eff > 0.0 && is_damage { server_emitter.emit(ServerEvent::Damage { uid: *uid, change: HealthChange { diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index ba55782e50..ab32e81155 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -106,6 +106,7 @@ pub enum ParticleMode { Firefly = 10, Bee = 11, GroundShockwave = 12, + HealingBeam = 13, } impl ParticleMode { diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index a5c45fb843..a478b42bb8 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -112,6 +112,7 @@ impl ParticleMgr { // add new Particle self.maintain_body_particles(scene_data); self.maintain_boost_particles(scene_data); + self.maintain_beam_particles(scene_data); self.maintain_block_particles(scene_data, terrain); self.maintain_shockwave_particles(scene_data); } else { @@ -300,6 +301,39 @@ impl ParticleMgr { } } + fn maintain_beam_particles(&mut self, scene_data: &SceneData) { + let state = scene_data.state; + let ecs = state.ecs(); + let time = state.get_time(); + + for (pos, ori, character_state) in ( + &ecs.read_storage::(), + &ecs.read_storage::(), + &ecs.read_storage::(), + ) + .join() + { + if let CharacterState::BasicBeam(b) = character_state { + if b.buildup_duration == Duration::default() { + let scale = 5.0; + let particle_ori = b.particle_ori.unwrap_or(*ori.vec()); + for _ in 0..self.scheduler.heartbeats(Duration::from_millis(10)) { + for d in 0..((b.range * scale) as i32) { + self.particles.push( + Particle::new( + Duration::from_millis(10), + time, + ParticleMode::HealingBeam, + pos.0 + particle_ori * (d as f32) / scale, + ), + ); + } + } + } + } + } + } + #[allow(clippy::same_item_push)] // TODO: Pending review in #587 fn maintain_block_particles( &mut self,