From 87e6c692b280309754a3b4cad862c4cff2879194 Mon Sep 17 00:00:00 2001
From: Sam <samuelkeiffer@gmail.com>
Date: Sun, 24 Jan 2021 12:45:52 -0500
Subject: [PATCH] Beam particles now determined from beam segment rather than
 character state.

---
 common/src/comp/ability.rs      |   1 -
 common/src/states/basic_beam.rs |   7 ---
 voxygen/src/scene/particle.rs   | 105 ++++++++++++++++----------------
 3 files changed, 51 insertions(+), 62 deletions(-)

diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs
index b171a85b89..8e221167d4 100644
--- a/common/src/comp/ability.rs
+++ b/common/src/comp/ability.rs
@@ -1466,7 +1466,6 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
                 },
                 timer: Duration::default(),
                 stage_section: StageSection::Buildup,
-                particle_ori: None::<Vec3<f32>>,
                 offset: Vec3::zero(),
             }),
         }
diff --git a/common/src/states/basic_beam.rs b/common/src/states/basic_beam.rs
index fa430ddfb3..888dd4a16d 100644
--- a/common/src/states/basic_beam.rs
+++ b/common/src/states/basic_beam.rs
@@ -60,8 +60,6 @@ pub struct Data {
     pub timer: Duration,
     /// What section the character stage is in
     pub stage_section: StageSection,
-    /// Used for particle stuffs
-    pub particle_ori: Option<Vec3<f32>>,
     /// Used to offset beam and particles
     pub offset: Vec3<f32>,
 }
@@ -105,7 +103,6 @@ impl CharacterBehavior for Data {
                             .timer
                             .checked_add(Duration::from_secs_f32(data.dt.0))
                             .unwrap_or_default(),
-                        particle_ori: Some(*data.inputs.look_dir),
                         ..*self
                     });
                 } else {
@@ -125,7 +122,6 @@ impl CharacterBehavior for Data {
                     update.character = CharacterState::BasicBeam(Data {
                         timer: Duration::default(),
                         stage_section: StageSection::Cast,
-                        particle_ori: Some(*data.inputs.look_dir),
                         offset: body_offsets,
                         ..*self
                     });
@@ -203,7 +199,6 @@ impl CharacterBehavior for Data {
                             .timer
                             .checked_add(Duration::from_secs_f32(data.dt.0))
                             .unwrap_or_default(),
-                        particle_ori: Some(*data.inputs.look_dir),
                         offset: body_offsets,
                         ..*self
                     });
@@ -217,7 +212,6 @@ impl CharacterBehavior for Data {
                     update.character = CharacterState::BasicBeam(Data {
                         timer: Duration::default(),
                         stage_section: StageSection::Recover,
-                        particle_ori: Some(*data.inputs.look_dir),
                         ..*self
                     });
                 }
@@ -229,7 +223,6 @@ impl CharacterBehavior for Data {
                             .timer
                             .checked_add(Duration::from_secs_f32(data.dt.0))
                             .unwrap_or_default(),
-                        particle_ori: Some(*data.inputs.look_dir),
                         ..*self
                     });
                 } else {
diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs
index 9ae5e1d97d..0f79b4a1f8 100644
--- a/voxygen/src/scene/particle.rs
+++ b/voxygen/src/scene/particle.rs
@@ -8,13 +8,12 @@ use crate::{
 };
 use common::{
     assets::{AssetExt, DotVoxAsset},
-    comp::{item::Reagent, object, Body, CharacterState, Ori, Pos, Shockwave},
+    comp::{item::Reagent, object, BeamSegment, Body, CharacterState, Ori, Pos, Shockwave},
     figure::Segment,
     outcome::Outcome,
     resources::DeltaTime,
     span,
     spiral::Spiral2d,
-    states::utils::StageSection,
     terrain::TerrainChunk,
     vol::{RectRasterableVol, SizedVol},
 };
@@ -366,65 +365,63 @@ impl ParticleMgr {
         let state = scene_data.state;
         let ecs = state.ecs();
         let time = state.get_time();
+        let dt = scene_data.state.ecs().fetch::<DeltaTime>().0;
 
-        for (pos, ori, character_state) in (
+        for (pos, ori, beam) in (
             &ecs.read_storage::<Pos>(),
             &ecs.read_storage::<Ori>(),
-            &ecs.read_storage::<CharacterState>(),
+            &ecs.read_storage::<BeamSegment>(),
         )
             .join()
+            .filter(|(_, _, b)| b.creation.map_or(true, |c| (c + dt as f64) >= time))
         {
-            if let CharacterState::BasicBeam(b) = character_state {
-                let particle_ori = b.particle_ori.unwrap_or_else(|| ori.look_vec());
-                if b.stage_section == StageSection::Cast {
-                    if b.static_data.base_hps > 0.0 {
-                        // Emit a light when using healing
-                        lights.push(Light::new(pos.0 + b.offset, Rgb::new(0.1, 1.0, 0.15), 1.0));
-                        for i in 0..self.scheduler.heartbeats(Duration::from_millis(1)) {
-                            self.particles.push(Particle::new_beam(
-                                b.static_data.beam_duration,
-                                time + i as f64 / 1000.0,
-                                ParticleMode::HealingBeam,
-                                pos.0 + particle_ori * 0.5 + b.offset,
-                                pos.0 + particle_ori * b.static_data.range + b.offset,
-                            ));
-                        }
-                    } else {
-                        let mut rng = thread_rng();
-                        let (from, to) = (Vec3::<f32>::unit_z(), particle_ori);
-                        let m = Mat3::<f32>::rotation_from_to_3d(from, to);
-                        // Emit a light when using flames
-                        lights.push(Light::new(
-                            pos.0 + b.offset,
-                            Rgb::new(1.0, 0.25, 0.05).map(|e| e * rng.gen_range(0.8..1.2)),
-                            2.0,
-                        ));
-                        self.particles.resize_with(
-                            self.particles.len()
-                                + 2 * usize::from(
-                                    self.scheduler.heartbeats(Duration::from_millis(1)),
-                                ),
-                            || {
-                                let phi: f32 =
-                                    rng.gen_range(0.0..b.static_data.max_angle.to_radians());
-                                let theta: f32 = rng.gen_range(0.0..2.0 * PI);
-                                let offset_z = Vec3::new(
-                                    phi.sin() * theta.cos(),
-                                    phi.sin() * theta.sin(),
-                                    phi.cos(),
-                                );
-                                let random_ori = offset_z * m * Vec3::new(-1.0, -1.0, 1.0);
-                                Particle::new_beam(
-                                    b.static_data.beam_duration,
-                                    time,
-                                    ParticleMode::FlameThrower,
-                                    pos.0 + random_ori * 0.5 + b.offset,
-                                    pos.0 + random_ori * b.static_data.range + b.offset,
-                                )
-                            },
-                        );
-                    }
+            let range = beam.properties.speed * beam.properties.duration.as_secs_f32();
+            if beam.properties.lifesteal_eff > 0.0 {
+                // Emit a light when using healing
+                lights.push(Light::new(pos.0, Rgb::new(0.1, 1.0, 0.15), 1.0));
+                for i in 0..self.scheduler.heartbeats(Duration::from_millis(1)) {
+                    self.particles.push(Particle::new_beam(
+                        beam.properties.duration,
+                        time + i as f64 / 1000.0,
+                        ParticleMode::HealingBeam,
+                        pos.0 + *ori.0 * 0.5,
+                        pos.0 + *ori.0 * range,
+                    ));
                 }
+            } else {
+                let mut rng = thread_rng();
+                let (from, to) = (Vec3::<f32>::unit_z(), *ori.0);
+                let m = Mat3::<f32>::rotation_from_to_3d(from, to);
+                // Emit a light when using flames
+                lights.push(Light::new(
+                    pos.0,
+                    Rgb::new(1.0, 0.25, 0.05).map(|e| e * rng.gen_range(0.8, 1.2)),
+                    2.0,
+                ));
+                self.particles.resize_with(
+                    self.particles.len()
+                        + 2 * usize::from(
+                            self.scheduler.heartbeats(Duration::from_millis(1)),
+                        ),
+                    || {
+                        let phi: f32 =
+                            rng.gen_range(0.0, beam.properties.angle.to_radians());
+                        let theta: f32 = rng.gen_range(0.0, 2.0 * PI);
+                        let offset_z = Vec3::new(
+                            phi.sin() * theta.cos(),
+                            phi.sin() * theta.sin(),
+                            phi.cos(),
+                        );
+                        let random_ori = offset_z * m * Vec3::new(-1.0, -1.0, 1.0);
+                        Particle::new_beam(
+                            beam.properties.duration,
+                            time,
+                            ParticleMode::FlameThrower,
+                            pos.0 + random_ori,
+                            pos.0 + random_ori * range,
+                        )
+                    },
+                );
             }
         }
     }