diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index f0a752c104..49a85e3085 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -73,6 +73,7 @@ const int ICE_SPIKES = 31; const int DRIP = 32; const int TORNADO = 33; const int DEATH = 34; +const int ENERGY_BUFFING = 35; // meters per second squared (acceleration) const float earth_gravity = 9.807; @@ -568,6 +569,16 @@ void main() { spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9) ); break; + case ENERGY_BUFFING: + f_reflect = 0.0; + spiral_radius = start_end(1 - pow(abs(rand5), 5), 1) * length(inst_dir); + attr = Attr( + spiral_motion(vec3(0, 0, rand3 + 1), spiral_radius, lifetime, abs(rand0), rand1 * 2 * PI) + vec3(0, 0, rand2), + vec3(6 * abs(rand4) * (1 - slow_start(2)) * pow(spiral_radius / length(inst_dir), 0.5)), + vec4(vec3(1.4), 1), + spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3) + ); + break; default: attr = Attr( linear_motion( diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index 06e4058b3e..c3f4b4e595 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -777,6 +777,14 @@ impl Body { Body::Arthropod(_) => true, _ => false, }, + BuffKind::Regeneration | BuffKind::ProtectingWard | BuffKind::Hastened => matches!( + self, + Body::Object( + object::Body::GnarlingTotemRed + | object::Body::GnarlingTotemGreen + | object::Body::GnarlingTotemWhite + ) + ), _ => false, } } diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index 677eaad62f..05128b8834 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -85,6 +85,7 @@ pub enum ParticleMode { Drip = 32, Tornado = 33, Death = 34, + EnergyBuffing = 35, } impl ParticleMode { diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 8b8c3895c6..18ec03b502 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -910,6 +910,7 @@ impl ParticleMgr { let ecs = state.ecs(); let time = state.get_time(); let mut rng = thread_rng(); + let dt = scene_data.state.get_delta_time(); for (pos, auras) in ( &ecs.read_storage::(), @@ -945,6 +946,16 @@ impl ParticleMgr { kind: buff::BuffKind::Regeneration, .. } => { + if auras.auras.iter().any(|(_, aura)| { + matches!(aura.aura_kind, aura::AuraKind::Buff { + kind: buff::BuffKind::ProtectingWard, + .. + }) + }) { + // If same entity has both protecting ward and regeneration auras, skip + // particles for regeneration + continue; + } let heartbeats = self.scheduler.heartbeats(Duration::from_millis(5)); self.particles.resize_with( self.particles.len() @@ -963,6 +974,56 @@ impl ParticleMgr { }, ); }, + aura::AuraKind::Buff { + kind: buff::BuffKind::Burning, + .. + } => { + let num_particles = aura.radius.powi(2) * dt / inline_tweak::tweak!(20.0); + self.particles.resize_with( + self.particles.len() + num_particles as usize, + || { + let rand_pos = { + let mut x = (rng.gen::() - 0.5) * 2.0; + let mut y = (rng.gen::() - 0.5) * 2.0; + while (x.powi(2) + y.powi(2)) > 1.0 { + x = (rng.gen::() - 0.5) * 2.0; + y = (rng.gen::() - 0.5) * 2.0; + } + Vec2::new(x, y) * aura.radius + pos.0.xy() + }; + let max_dur = Duration::from_secs(1); + Particle::new_directed( + aura.duration.map_or(max_dur, |dur| dur.min(max_dur)), + time, + ParticleMode::FlameThrower, + rand_pos.with_z(pos.0.z), + rand_pos.with_z(pos.0.z + 1.0), + ) + }, + ); + }, + aura::AuraKind::Buff { + kind: buff::BuffKind::Hastened, + .. + } => { + let heartbeats = self.scheduler.heartbeats(Duration::from_millis(5)); + self.particles.resize_with( + self.particles.len() + + aura.radius.powi(2) as usize * usize::from(heartbeats) / 300, + || { + let rand_dist = aura.radius * (1.0 - rng.gen::().powi(100)); + let init_pos = Vec3::new(rand_dist, 0_f32, 0_f32); + let max_dur = Duration::from_secs(1); + Particle::new_directed( + aura.duration.map_or(max_dur, |dur| dur.min(max_dur)), + time, + ParticleMode::EnergyBuffing, + pos.0, + pos.0 + init_pos, + ) + }, + ); + }, _ => {}, } } diff --git a/world/src/site2/plot/gnarling.rs b/world/src/site2/plot/gnarling.rs index 0096b8a1ad..6abca571e4 100644 --- a/world/src/site2/plot/gnarling.rs +++ b/world/src/site2/plot/gnarling.rs @@ -385,7 +385,10 @@ impl GnarlingFortification { supplement.add_entity(random_gnarling(wpos, dynamic_rng)); }, GnarlingStructure::ChieftainHut => { - supplement.add_entity(gnarling_chieftain(wpos, dynamic_rng)); + supplement.add_entity(gnarling_chieftain( + wpos.xy().with_z(wpos.z + 8), + dynamic_rng, + )); let left_inner_guard_pos = wpos + ori.dir() * 8 + ori.cw().dir() * 2; supplement.add_entity(wood_golem(left_inner_guard_pos, dynamic_rng)); let right_inner_guard_pos = wpos + ori.dir() * 8 + ori.ccw().dir() * 2;