From e92116cd1d9deb374e91d6e98d3ac857bf96d8a0 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 29 Aug 2020 15:44:46 -0500 Subject: [PATCH] Tweaked particles. Added skill icons. --- assets/voxygen/element/icons/heal_bomb.png | Bin 0 -> 1866 bytes assets/voxygen/shaders/particle-vert.glsl | 40 ++++++- common/src/comp/body/object.rs | 5 +- common/src/comp/inventory/item/tool.rs | 6 +- common/src/outcome.rs | 1 + common/src/states/basic_beam.rs | 5 +- common/src/sys/projectile.rs | 42 +++---- server/src/events/entity_manipulation.rs | 12 +- server/src/events/mod.rs | 10 +- voxygen/src/hud/img_ids.rs | 1 + voxygen/src/hud/skillbar.rs | 10 +- voxygen/src/render/pipelines/particle.rs | 21 ++++ voxygen/src/scene/figure/load.rs | 1 + voxygen/src/scene/mod.rs | 1 + voxygen/src/scene/particle.rs | 122 ++++++++++++++------- 15 files changed, 201 insertions(+), 76 deletions(-) create mode 100644 assets/voxygen/element/icons/heal_bomb.png diff --git a/assets/voxygen/element/icons/heal_bomb.png b/assets/voxygen/element/icons/heal_bomb.png new file mode 100644 index 0000000000000000000000000000000000000000..2de46351542294a7b0d1ac692c5b9c49f478b086 GIT binary patch literal 1866 zcmbVNZD`zN9M6i?IjIgeWE9buDp=cGUN4u#-e!AO*HiB-?X53LTXRpI+{NA{S(5gy zWfh#l*0M4X+`5;FFQbDgL#<4qOl6Es{UD=Os7%Iu9dxkK4?{ob=97D~tKAC*l012y z-}C$b{x8ozqph*cRcor(U>H^vX$iNX_j>PMU4fnz7sp;eue+_5ZU@8eS?ArWu>A)& zU|8j%9`ACyqR+{|%=i@5Oh8{QV<9w#HEhaR3h0L}o`6Z+2ojfPz94X24HBLHC>^yz zFr~K)+pv8&76-%qKvIcK8}Wvmj0iH&Rq$LUZ8&l+NaT5CH1?(`0?$L-{vgrl8N|Dy zt$4_^Aujl663{e@2P7XO@Vr3R<1Ee66z!)NmShB(=4B>;7cT-?vsF!Q3qM`7g}#DB z%5^Q7qO#enFU$E%J4rE;BvCX=u`G!Yq%&l=N{%#~ni4}8I>6Q~S2qpZV^k96fEy%` z(t-;at4wP+#W10OQ8~q;7$5Dqln1JyjI##pbl$iMD42#BXt)l-GG(llGF{V2nKz&= zFJET>g*F;3+gMRcCQ~-yxXpvejbcDnL_6^z3sP;+F$Zh_n+K818qXU`4%tv~O*?Ly z=~ALvOOkPx@v->how}i#S*Lc%1{hXc7$m%`k+ev%{y4+STtMdNI+~Sfx&V!us;&(! zgNkvMll{ER^4CF8$*78}+!Cw;Su^d7f*jT}N)l3*ktFbP80C}WspFQ;M?#@i z+tlAEVj37*j;h9mtz6G>j+ z6Qsz}fK&h@vH_J-1XU~T51U}XD*~Qy09B$mt*;P|+p=8TpG`qTdXp+CSa(d# z%_=r*OrqG`vI?miiFcI2n@hjFR2DQXlm6eT{Xf!+VF4+{NJ7+MDZ+Dx@_JDrDb(_O z<=2+HW`@@n1W3Ef9BB-&rW{RaObhz#vh;k zeEzU>s5<*Z^8ExiziRsQW9Mq6zJqfU$7?TL?B3GRweakP*bm!|{55d@2Yv7C%~TtU zS4MuX`tEAy!fW%1?k&eYpX=V!(lr>HxE!xk$G7ggatE>Nx4U{z^!z>2c;tZhw~I8# K!bh84+Wrq^>2AmX literal 0 HcmV?d00001 diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index 4aa5154394..2e326a9193 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -23,6 +23,7 @@ in vec3 inst_pos; in float inst_time; in float inst_lifespan; in float inst_entropy; +in float inst_misc; in int inst_mode; out vec3 f_pos; @@ -49,6 +50,7 @@ const int FIREFLY = 10; const int BEE = 11; const int GROUND_SHOCKWAVE = 12; const int HEALING_BEAM = 13; +const int ENERGY_NATURE = 14; // meters per second squared (acceleration) const float earth_gravity = 9.807; @@ -104,6 +106,28 @@ mat4 identity() { ); } +vec3 beam_pos2() { + return vec3(inst_lifespan, inst_entropy, inst_misc); +} + +vec3 perp_axis1(vec3 axis) { + return normalize(vec3(axis.y + axis.z, -axis.x + axis.z, -axis.x - axis.y)); +} + +vec3 perp_axis2(vec3 axis1, vec3 axis2) { + return normalize(vec3(axis1.y * axis2.z - axis1.z * axis2.y, axis1.z * axis2.x - axis1.x * axis2.z, axis1.x * axis2.y - axis1.y * axis2.x)); +} + +vec3 spiral_motion(vec3 line, float radius, float time_function) { + vec3 axis2 = perp_axis1(line); + vec3 axis3 = perp_axis2(line, axis2); + + return line * time_function + vec3( + radius * cos(10 * time_function) * axis2.x + radius * sin(10 * time_function) * axis3.x, + radius * cos(10 * time_function) * axis2.y + radius * sin(10 * time_function) * axis3.y, + radius * cos(10 * time_function) * axis2.z + radius * sin(10 * time_function) * axis3.z + 1.0); +} + void main() { float rand0 = hash(vec4(inst_entropy + 0)); float rand1 = hash(vec4(inst_entropy + 1)); @@ -251,10 +275,20 @@ void main() { ); } else if (inst_mode == HEALING_BEAM) { attr = Attr( - vec3(rand0 * lifetime * 15, rand1 * lifetime * 15, rand2 * lifetime * 15 + 1), - 1 + rand3, + spiral_motion(beam_pos2() - inst_pos, 0.3 * (floor(2 * hash(vec4(inst_time)) + 0.5) - 0.5), lifetime / 2), + (1.7 - 0.7 * abs(floor(2 * hash(vec4(inst_time)) - 0.5) + 0.5)) * (1.5 + 0.5 * sin(tick.x * 10 - lifetime * 4)), + vec4(vec3(0, 0.7 + 0.3 * sin(tick.x * 8 - lifetime * 3), 0), 1), + spin_in_axis(vec3(inst_entropy, inst_misc, inst_lifespan), tick.z) + ); + } else if (inst_mode == ENERGY_NATURE) { + attr = Attr( + linear_motion( + vec3(rand0 * 1, rand1 * 1, rand2 * 1), + vec3(rand3 * 2, rand4 * 2, rand5 * 2) + ), + 0.8, vec4(vec3(0, 1, 0), 1), - spin_in_axis(vec3(1, 0, 0), 0) + spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3) ); } else { attr = Attr( diff --git a/common/src/comp/body/object.rs b/common/src/comp/body/object.rs index 474a22380f..64ff313920 100644 --- a/common/src/comp/body/object.rs +++ b/common/src/comp/body/object.rs @@ -67,6 +67,7 @@ make_case_elim!( FireworkRed = 57, FireworkYellow = 58, MultiArrow = 59, + BoltNature = 60, } ); @@ -77,7 +78,7 @@ impl Body { } } -pub const ALL_OBJECTS: [Body; 60] = [ +pub const ALL_OBJECTS: [Body; 61] = [ Body::Arrow, Body::Bomb, Body::Scarecrow, @@ -138,6 +139,7 @@ pub const ALL_OBJECTS: [Body; 60] = [ Body::FireworkRed, Body::FireworkYellow, Body::MultiArrow, + Body::BoltNature, ]; impl From for super::Body { @@ -207,6 +209,7 @@ impl Body { Body::FireworkRed => "firework_red", Body::FireworkYellow => "firework_yellow", Body::MultiArrow => "multi_arrow", + Body::BoltNature => "bolt_nature", } } } diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index cbf89e4b05..de2e9c80c5 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -314,7 +314,7 @@ impl Tool { energy_regen: 120, }, BasicRanged { - energy_cost: 400, + energy_cost: 0, holdable: true, prepare_duration: Duration::from_millis(800), recover_duration: Duration::from_millis(50), @@ -337,12 +337,12 @@ impl Tool { owner: None, ignore_group: true, }, - projectile_body: Body::Object(object::Body::BoltFireBig), + projectile_body: Body::Object(object::Body::BoltNature), projectile_light: Some(LightEmitter { col: (0.0, 1.0, 0.0).into(), ..Default::default() }), - projectile_gravity: None, + projectile_gravity: Some(Gravity(1.0)), projectile_speed: 25.0, }, ] diff --git a/common/src/outcome.rs b/common/src/outcome.rs index 6088e99959..f61169905c 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -14,6 +14,7 @@ pub enum Outcome { pos: Vec3, power: f32, reagent: Option, // How can we better define this? + percent_damage: f32, }, ProjectileShot { pos: Vec3, diff --git a/common/src/states/basic_beam.rs b/common/src/states/basic_beam.rs index e8651d5f2d..7a73e96eff 100644 --- a/common/src/states/basic_beam.rs +++ b/common/src/states/basic_beam.rs @@ -94,7 +94,8 @@ impl CharacterBehavior for Data { lifesteal_eff: self.lifesteal_eff, energy_regen: self.energy_regen, }); - } else if data.inputs.primary.is_pressed() && self.cooldown_duration != Duration::default() { + } 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, @@ -158,8 +159,6 @@ impl CharacterBehavior for Data { data.updater.remove::(data.entity); } - - update } } diff --git a/common/src/sys/projectile.rs b/common/src/sys/projectile.rs index 9e7869026e..a0830c0af0 100644 --- a/common/src/sys/projectile.rs +++ b/common/src/sys/projectile.rs @@ -133,16 +133,17 @@ impl<'a> System<'a> for Sys { energy_mut.change_by(energy as i32, EnergySource::HitEnemy); } }, - projectile::Effect::Explode { power, percent_damage } => { - server_emitter.emit(ServerEvent::Explosion { - pos: pos.0, - power, - owner: projectile.owner, - friendly_damage: false, - reagent: None, - percent_damage, - }) - }, + projectile::Effect::Explode { + power, + percent_damage, + } => server_emitter.emit(ServerEvent::Explosion { + pos: pos.0, + power, + owner: projectile.owner, + friendly_damage: false, + reagent: None, + percent_damage, + }), projectile::Effect::Vanish => server_emitter.emit(ServerEvent::Destroy { entity, cause: HealthSource::World, @@ -163,16 +164,17 @@ impl<'a> System<'a> for Sys { if physics.on_wall.is_some() || physics.on_ground || physics.on_ceiling { for effect in projectile.hit_solid.drain(..) { match effect { - projectile::Effect::Explode { power, percent_damage } => { - server_emitter.emit(ServerEvent::Explosion { - pos: pos.0, - power, - owner: projectile.owner, - friendly_damage: false, - reagent: None, - percent_damage, - }) - }, + projectile::Effect::Explode { + power, + percent_damage, + } => server_emitter.emit(ServerEvent::Explosion { + pos: pos.0, + power, + owner: projectile.owner, + friendly_damage: false, + reagent: None, + percent_damage, + }), projectile::Effect::Vanish => server_emitter.emit(ServerEvent::Destroy { entity, cause: HealthSource::World, diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index ac3524306f..235564abd8 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -462,6 +462,7 @@ pub fn handle_explosion( pos, power, reagent, + percent_damage, }); let owner_entity = owner.and_then(|uid| { ecs.read_resource::() @@ -486,9 +487,14 @@ pub fn handle_explosion( && distance_squared < hit_range.powi(2) { // See if entities are in the same group - let same_group = owner_entity - .and_then(|e| groups.get(e)) - .map_or(false, |group_a| Some(group_a) == groups.get(entity_b)); + let mut same_group = owner_entity + .and_then(|e| groups.get(e)) + .map_or(false, |group_a| Some(group_a) == groups.get(entity_b)); + if let Some(entity) = owner_entity { + if entity == entity_b { + same_group = true; + } + } // Don't heal if outside group // Don't damage in the same group let (mut is_heal, mut is_damage) = (false, false); diff --git a/server/src/events/mod.rs b/server/src/events/mod.rs index 11158f44c2..1df14c098c 100644 --- a/server/src/events/mod.rs +++ b/server/src/events/mod.rs @@ -61,7 +61,15 @@ impl Server { friendly_damage, reagent, percent_damage, - } => handle_explosion(&self, pos, power, owner, friendly_damage, reagent, percent_damage), + } => handle_explosion( + &self, + pos, + power, + owner, + friendly_damage, + reagent, + percent_damage, + ), ServerEvent::Shoot { entity, dir, diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index 0b12a0696b..3a2e21382b 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -268,6 +268,7 @@ image_ids! { snake_arrow_0: "voxygen.element.icons.snake", heal_0: "voxygen.element.icons.heal_0", sword_whirlwind: "voxygen.element.icons.sword_whirlwind", + heal_bomb: "voxygen.element.icons.heal_bomb", // Buttons button: "voxygen.element.buttons.button", diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 9b83cb5e43..6f6f25b061 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -620,7 +620,11 @@ impl<'a> Widget for Skillbar<'a> { ToolKind::Hammer(_) => self.imgs.twohhammer_m1, ToolKind::Axe(_) => self.imgs.twohaxe_m1, ToolKind::Bow(_) => self.imgs.bow_m1, - ToolKind::Staff(_) => self.imgs.staff_m1, + ToolKind::Staff(kind) => match kind.as_ref() { + "Sceptre" => self.imgs.heal_0, + "SceptreVelorite" => self.imgs.heal_0, + _ => self.imgs.staff_m1, + }, ToolKind::Debug(kind) => match kind.as_ref() { "Boost" => self.imgs.flyingrod_m1, _ => self.imgs.nothing, @@ -699,8 +703,8 @@ impl<'a> Widget for Skillbar<'a> { Some(ToolKind::Axe(_)) => self.imgs.axespin, Some(ToolKind::Bow(_)) => self.imgs.bow_m2, Some(ToolKind::Staff(kind)) => match kind.as_ref() { - "Sceptre" => self.imgs.heal_0, - "SceptreVelorite" => self.imgs.heal_0, + "Sceptre" => self.imgs.heal_bomb, + "SceptreVelorite" => self.imgs.heal_bomb, _ => self.imgs.staff_m2, }, Some(ToolKind::Debug(kind)) => match kind.as_ref() { diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index ab32e81155..2bd17548cf 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -35,6 +35,9 @@ gfx_defines! { // can save 32 bits per instance, and have cleaner tailor made code. inst_mode: i32 = "inst_mode", + // an extra value for particles that need it + inst_misc: f32 = "inst_misc", + // a triangle is: f32 x 3 x 3 x 1 = 288 bits // a quad is: f32 x 3 x 3 x 2 = 576 bits // a cube is: f32 x 3 x 3 x 12 = 3456 bits @@ -107,6 +110,7 @@ pub enum ParticleMode { Bee = 11, GroundShockwave = 12, HealingBeam = 13, + EnergyNature = 14, } impl ParticleMode { @@ -127,6 +131,23 @@ impl Instance { inst_entropy: rand::thread_rng().gen(), inst_mode: inst_mode as i32, inst_pos: inst_pos.into_array(), + inst_misc: 0.0, + } + } + + pub fn new_beam( + inst_time: f64, + inst_mode: ParticleMode, + inst_pos: Vec3, + inst_pos2: Vec3, + ) -> Self { + Self { + inst_time: inst_time as f32, + inst_mode: inst_mode as i32, + inst_pos: inst_pos.into_array(), + inst_lifespan: inst_pos2.x, + inst_entropy: inst_pos2.y, + inst_misc: inst_pos2.z, } } } diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 1d77fe0f0f..68d24bbb87 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -3588,6 +3588,7 @@ fn mesh_object(obj: &object::Body) -> BoneMeshes { Body::BoltFireBig => ("weapon.projectile.fire-bolt-1", Vec3::new(-6.0, -6.0, -6.0)), Body::TrainingDummy => ("object.training_dummy", Vec3::new(-7.0, -5.0, 0.0)), Body::MultiArrow => ("weapon.projectile.multi-arrow", Vec3::new(-4.0, -9.5, -5.0)), + Body::BoltNature => ("weapon.projectile.nature-bolt", Vec3::new(-6.0, -6.0, -6.0)), }; load_mesh(name, offset) } diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 35dd68c32f..9757957998 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -390,6 +390,7 @@ impl Scene { pos, power, reagent, + .. } => self.event_lights.push(EventLight { light: Light::new( *pos, diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 08eddafa93..953c4ec934 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -58,37 +58,50 @@ impl ParticleMgr { pos, power, reagent, + percent_damage, } => { - self.particles.resize_with( - self.particles.len() + if reagent.is_some() { 300 } else { 150 }, - || { + if *percent_damage < 0.5 { + self.particles.resize_with(self.particles.len() + 200, || { Particle::new( - Duration::from_millis(if reagent.is_some() { 1000 } else { 250 }), + Duration::from_secs(1), time, - match reagent { - Some(Reagent::Blue) => ParticleMode::FireworkBlue, - Some(Reagent::Green) => ParticleMode::FireworkGreen, - Some(Reagent::Purple) => ParticleMode::FireworkPurple, - Some(Reagent::Red) => ParticleMode::FireworkRed, - Some(Reagent::Yellow) => ParticleMode::FireworkYellow, - None => ParticleMode::Shrapnel, - }, - *pos, + ParticleMode::EnergyNature, + *pos + Vec3::::zero().map(|_| rng.gen_range(-3.0, 3.0) * power), ) - }, - ); + }); + } else { + self.particles.resize_with( + self.particles.len() + if reagent.is_some() { 300 } else { 150 }, + || { + Particle::new( + Duration::from_millis(if reagent.is_some() { 1000 } else { 250 }), + time, + match reagent { + Some(Reagent::Blue) => ParticleMode::FireworkBlue, + Some(Reagent::Green) => ParticleMode::FireworkGreen, + Some(Reagent::Purple) => ParticleMode::FireworkPurple, + Some(Reagent::Red) => ParticleMode::FireworkRed, + Some(Reagent::Yellow) => ParticleMode::FireworkYellow, + None => ParticleMode::Shrapnel, + }, + *pos, + ) + }, + ); - self.particles.resize_with( - self.particles.len() + if reagent.is_some() { 100 } else { 200 }, - || { - Particle::new( - Duration::from_secs(4), - time, - ParticleMode::CampfireSmoke, - *pos + Vec2::::zero().map(|_| rng.gen_range(-1.0, 1.0) * power), - ) - }, - ); + self.particles.resize_with( + self.particles.len() + if reagent.is_some() { 100 } else { 200 }, + || { + Particle::new( + Duration::from_secs(4), + time, + ParticleMode::CampfireSmoke, + *pos + Vec2::::zero() + .map(|_| rng.gen_range(-1.0, 1.0) * power), + ) + }, + ); + } }, Outcome::ProjectileShot { .. } => {}, } @@ -144,6 +157,9 @@ impl ParticleMgr { Body::Object(object::Body::BoltFireBig) => { self.maintain_boltfirebig_particles(scene_data, pos) }, + Body::Object(object::Body::BoltNature) => { + self.maintain_boltnature_particles(scene_data, pos) + }, Body::Object( object::Body::Bomb | object::Body::FireworkBlue @@ -241,6 +257,21 @@ impl ParticleMgr { ); } + fn maintain_boltnature_particles(&mut self, scene_data: &SceneData, pos: &Pos) { + let time = scene_data.state.get_time(); + + // nature + self.particles.resize( + self.particles.len() + usize::from(self.scheduler.heartbeats(Duration::from_millis(3))), + Particle::new( + Duration::from_millis(250), + time, + ParticleMode::EnergyNature, + pos.0, + ), + ); + } + fn maintain_bomb_particles(&mut self, scene_data: &SceneData, pos: &Pos) { span!( _guard, @@ -314,19 +345,19 @@ impl ParticleMgr { .join() { if let CharacterState::BasicBeam(b) = character_state { - if b.buildup_duration == Duration::default() { - 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 as i32) { - self.particles.push( - Particle::new( - Duration::from_millis(50), - time, - ParticleMode::HealingBeam, - pos.0 + particle_ori * (d as f32), - ), - ); - } + let particle_ori = b.particle_ori.unwrap_or(*ori.vec()); + for _ in 0..self.scheduler.heartbeats(Duration::from_millis(5)) { + let buildup = b.buildup_duration.as_millis() as i32; + for t in 0..((buildup / 50) + 1) { + let frac = ((t * 50) as f32) / 250.0; // Default value of buildup duration hardcoded for now, as it currently decreases over time + let dur = (2000.0 * (1.0 - frac)).max(0.0) as u64; + self.particles.push(Particle::new_beam( + Duration::from_millis(dur), + time, + ParticleMode::HealingBeam, + pos.0 + particle_ori * b.range * frac, + pos.0 + particle_ori * b.range, + )); } } } @@ -679,4 +710,17 @@ impl Particle { instance: ParticleInstance::new(time, lifespan.as_secs_f32(), mode, pos), } } + + fn new_beam( + lifespan: Duration, + time: f64, + mode: ParticleMode, + pos1: Vec3, + pos2: Vec3, + ) -> Self { + Particle { + alive_until: time + lifespan.as_secs_f64(), + instance: ParticleInstance::new_beam(time, mode, pos1, pos2), + } + } }