mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Particles for lifesteal beam. Changed how frontend recognized beams.
This commit is contained in:
parent
18edc1092b
commit
c6a222340e
@ -8,4 +8,5 @@ HealingBeam(
|
||||
max_angle: 1.0,
|
||||
lifesteal_eff: 0.0,
|
||||
energy_cost: 50,
|
||||
specifier: HealingBeam,
|
||||
)
|
@ -10,4 +10,5 @@ BasicBeam(
|
||||
energy_regen: 25,
|
||||
energy_drain: 0,
|
||||
orientation_behavior: Normal,
|
||||
specifier: LifestealBeam
|
||||
)
|
@ -10,4 +10,5 @@ BasicBeam(
|
||||
energy_regen: 0,
|
||||
energy_drain: 350,
|
||||
orientation_behavior: Normal,
|
||||
specifier: Flamethrower,
|
||||
)
|
@ -10,4 +10,5 @@ BasicBeam(
|
||||
energy_regen: 0,
|
||||
energy_drain: 350,
|
||||
orientation_behavior: Normal,
|
||||
specifier: Flamethrower,
|
||||
)
|
||||
|
@ -12,4 +12,5 @@ BasicBeam(
|
||||
//energy_cost: 50,
|
||||
energy_drain: 0,
|
||||
orientation_behavior: Normal,
|
||||
specifier: HealingBeam,
|
||||
)
|
@ -10,4 +10,5 @@ BasicBeam(
|
||||
energy_regen: 0,
|
||||
energy_drain: 0,
|
||||
orientation_behavior: Normal,
|
||||
specifier: Flamethrower,
|
||||
)
|
@ -10,4 +10,5 @@ BasicBeam(
|
||||
energy_regen: 0,
|
||||
energy_drain: 0,
|
||||
orientation_behavior: Turret,
|
||||
specifier: Flamethrower,
|
||||
)
|
@ -60,6 +60,7 @@ const int FIRE_BOWL = 18;
|
||||
const int SNOW = 19;
|
||||
const int EXPLOSION = 20;
|
||||
const int ICE = 21;
|
||||
const int LIFESTEAL_BEAM = 22;
|
||||
|
||||
// meters per second squared (acceleration)
|
||||
const float earth_gravity = 9.807;
|
||||
@ -340,6 +341,14 @@ void main() {
|
||||
vec4(vec3(0.4, 1.6 + 0.3 * sin(tick.x * 10 - lifetime * 3 + 4), 1.0 + 0.15 * sin(tick.x * 5 - lifetime * 5)), 1 /*0.3*/),
|
||||
spin_in_axis(inst_dir, tick.z)
|
||||
);
|
||||
} else if (inst_mode == LIFESTEAL_BEAM) {
|
||||
f_reflect = 0.01;
|
||||
attr = Attr(
|
||||
spiral_motion(inst_dir, 0.3 * (floor(2 * rand0 + 0.5) - 0.5) * min(linear_scale(10), 1), lifetime / inst_lifespan, 10.0, inst_time),
|
||||
vec3((1.7 - 0.7 * abs(floor(2 * rand0 - 0.5) + 0.5)) * (1.5 + 0.5 * sin(tick.x * 10 - lifetime * 4))),
|
||||
vec4(vec3(1.0 + 0.3 * sin(tick.x + lifetime * 5), 1.25 + 0.2 * sin(tick.x * 10 - lifetime * 3 + 4), 0.7), 1 /*0.3*/),
|
||||
spin_in_axis(inst_dir, tick.z)
|
||||
);
|
||||
} else if (inst_mode == ENERGY_NATURE) {
|
||||
f_reflect = 0.0;
|
||||
attr = Attr(
|
||||
|
@ -2,8 +2,8 @@ use crate::{
|
||||
assets::{self, Asset},
|
||||
combat,
|
||||
comp::{
|
||||
aura, inventory::item::tool::ToolKind, projectile::ProjectileConstructor, skills, Body,
|
||||
CharacterState, EnergySource, Gravity, LightEmitter, StateUpdate,
|
||||
aura, beam, inventory::item::tool::ToolKind, projectile::ProjectileConstructor, skills,
|
||||
Body, CharacterState, EnergySource, Gravity, LightEmitter, StateUpdate,
|
||||
},
|
||||
states::{
|
||||
behavior::JoinData,
|
||||
@ -224,6 +224,7 @@ pub enum CharacterAbility {
|
||||
energy_regen: f32,
|
||||
energy_drain: f32,
|
||||
orientation_behavior: basic_beam::MovementBehavior,
|
||||
specifier: beam::FrontendSpecifier,
|
||||
},
|
||||
CastAura {
|
||||
buildup_duration: f32,
|
||||
@ -243,6 +244,7 @@ pub enum CharacterAbility {
|
||||
range: f32,
|
||||
max_angle: f32,
|
||||
energy_cost: f32,
|
||||
specifier: beam::FrontendSpecifier,
|
||||
},
|
||||
}
|
||||
|
||||
@ -1472,6 +1474,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
energy_regen,
|
||||
energy_drain,
|
||||
orientation_behavior,
|
||||
specifier,
|
||||
} => CharacterState::BasicBeam(basic_beam::Data {
|
||||
static_data: basic_beam::StaticData {
|
||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||
@ -1486,6 +1489,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
energy_drain: *energy_drain,
|
||||
ability_info,
|
||||
orientation_behavior: *orientation_behavior,
|
||||
specifier: *specifier,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
@ -1520,6 +1524,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
range,
|
||||
max_angle,
|
||||
energy_cost,
|
||||
specifier,
|
||||
} => CharacterState::HealingBeam(healing_beam::Data {
|
||||
static_data: healing_beam::StaticData {
|
||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||
@ -1531,6 +1536,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
max_angle: *max_angle,
|
||||
energy_cost: *energy_cost,
|
||||
ability_info,
|
||||
specifier: *specifier,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
|
@ -11,6 +11,7 @@ pub struct Properties {
|
||||
pub speed: f32,
|
||||
pub duration: Duration,
|
||||
pub owner: Option<Uid>,
|
||||
pub specifier: FrontendSpecifier,
|
||||
}
|
||||
|
||||
// TODO: Separate components out for cheaper network syncing
|
||||
@ -44,3 +45,10 @@ pub struct Beam {
|
||||
impl Component for Beam {
|
||||
type Storage = IdvStorage<Self>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum FrontendSpecifier {
|
||||
Flamethrower,
|
||||
LifestealBeam,
|
||||
HealingBeam,
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{comp, uid::Uid};
|
||||
use comp::item::Reagent;
|
||||
use comp::{beam, item::Reagent};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
@ -24,7 +24,7 @@ pub enum Outcome {
|
||||
},
|
||||
Beam {
|
||||
pos: Vec3<f32>,
|
||||
heal: bool,
|
||||
specifier: beam::FrontendSpecifier,
|
||||
},
|
||||
ExpChange {
|
||||
uid: Uid,
|
||||
|
@ -43,6 +43,8 @@ pub struct StaticData {
|
||||
pub orientation_behavior: MovementBehavior,
|
||||
/// What key is used to press ability
|
||||
pub ability_info: AbilityInfo,
|
||||
/// Used to specify the beam to the frontend
|
||||
pub specifier: beam::FrontendSpecifier,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -141,6 +143,7 @@ impl CharacterBehavior for Data {
|
||||
speed,
|
||||
duration: self.static_data.beam_duration,
|
||||
owner: Some(*data.uid),
|
||||
specifier: self.static_data.specifier,
|
||||
};
|
||||
// Gets offsets
|
||||
let body_offsets = match data.body {
|
||||
|
@ -33,6 +33,8 @@ pub struct StaticData {
|
||||
pub energy_cost: f32,
|
||||
/// What key is used to press ability
|
||||
pub ability_info: AbilityInfo,
|
||||
/// Used to specify the beam to the frontend
|
||||
pub specifier: beam::FrontendSpecifier,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -106,6 +108,7 @@ impl CharacterBehavior for Data {
|
||||
speed,
|
||||
duration: self.static_data.beam_duration,
|
||||
owner: Some(*data.uid),
|
||||
specifier: self.static_data.specifier,
|
||||
};
|
||||
// Gets offsets
|
||||
let body_offsets = match data.body {
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::{sys, Server, StateExt};
|
||||
use common::{
|
||||
character::CharacterId,
|
||||
combat,
|
||||
comp::{
|
||||
self,
|
||||
aura::{Aura, AuraKind, AuraTarget},
|
||||
@ -175,10 +174,7 @@ pub fn handle_beam(server: &mut Server, properties: beam::Properties, pos: Pos,
|
||||
let ecs = state.ecs();
|
||||
ecs.write_resource::<Vec<Outcome>>().push(Outcome::Beam {
|
||||
pos: pos.0,
|
||||
heal: properties
|
||||
.attack
|
||||
.effects()
|
||||
.any(|e| matches!(e.effect(), combat::CombatEffect::Heal(h) if *h > 0.0)),
|
||||
specifier: properties.specifier,
|
||||
});
|
||||
state.create_beam(properties, pos, ori).build();
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ use client::Client;
|
||||
use common::{
|
||||
assets::{self, AssetExt, AssetHandle},
|
||||
comp::{
|
||||
beam,
|
||||
item::{ItemKind, Reagent, ToolKind},
|
||||
object, Body, CharacterAbilityType, InventoryUpdateEvent,
|
||||
},
|
||||
@ -353,14 +354,15 @@ impl SfxMgr {
|
||||
let file_ref = "voxygen.audio.sfx.character.level_up_sound_-_shorter_wind_up";
|
||||
audio.play_sfx(file_ref, *pos, None);
|
||||
},
|
||||
Outcome::Beam { pos, heal } => {
|
||||
if *heal {
|
||||
Outcome::Beam { pos, specifier } => match specifier {
|
||||
beam::FrontendSpecifier::LifestealBeam | beam::FrontendSpecifier::HealingBeam => {
|
||||
let file_ref = "voxygen.audio.sfx.abilities.staff_channeling";
|
||||
audio.play_sfx(file_ref, *pos, None);
|
||||
} else {
|
||||
},
|
||||
beam::FrontendSpecifier::Flamethrower => {
|
||||
let file_ref = "voxygen.audio.sfx.abilities.flame_thrower";
|
||||
audio.play_sfx(file_ref, *pos, None);
|
||||
}
|
||||
},
|
||||
},
|
||||
Outcome::ExpChange { .. } => {},
|
||||
}
|
||||
|
@ -118,6 +118,7 @@ pub enum ParticleMode {
|
||||
Snow = 19,
|
||||
Explosion = 20,
|
||||
Ice = 21,
|
||||
LifestealBeam = 22,
|
||||
}
|
||||
|
||||
impl ParticleMode {
|
||||
|
@ -8,8 +8,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
assets::{AssetExt, DotVoxAsset},
|
||||
combat::CombatEffect,
|
||||
comp::{item::Reagent, object, BeamSegment, Body, CharacterState, Ori, Pos, Shockwave},
|
||||
comp::{beam, item::Reagent, object, BeamSegment, Body, CharacterState, Ori, Pos, Shockwave},
|
||||
figure::Segment,
|
||||
outcome::Outcome,
|
||||
resources::DeltaTime,
|
||||
@ -401,104 +400,70 @@ impl ParticleMgr {
|
||||
.join()
|
||||
.filter(|(_, _, b)| b.creation.map_or(true, |c| (c + dt as f64) >= time))
|
||||
{
|
||||
//
|
||||
// TODO: Handle this less hackily. Done this way as beam segments are created
|
||||
// every server tick, which is approximately 33 ms. Heartbeat scheduler used to
|
||||
// account for clients with less than 30 fps because they start the creation
|
||||
// time when the segments are received and could receive 2 at once
|
||||
let beam_tick_count = 33.max(self.scheduler.heartbeats(Duration::from_millis(1)));
|
||||
let range = beam.properties.speed * beam.properties.duration.as_secs_f32();
|
||||
if beam
|
||||
.properties
|
||||
.attack
|
||||
.effects()
|
||||
.any(|e| matches!(e.effect(), CombatEffect::Heal(h) if *h > 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_directed(
|
||||
beam.properties.duration,
|
||||
time + i as f64 / 1000.0,
|
||||
ParticleMode::HealingBeam,
|
||||
match beam.properties.specifier {
|
||||
beam::FrontendSpecifier::Flamethrower => {
|
||||
let mut rng = thread_rng();
|
||||
let (from, to) = (Vec3::<f32>::unit_z(), *ori.look_dir());
|
||||
let m = Mat3::<f32>::rotation_from_to_3d(from, to);
|
||||
// Emit a light when using flames
|
||||
lights.push(Light::new(
|
||||
pos.0,
|
||||
pos.0 + *ori.look_dir() * range,
|
||||
Rgb::new(1.0, 0.25, 0.05).map(|e| e * rng.gen_range(0.8..1.2)),
|
||||
2.0,
|
||||
));
|
||||
/*
|
||||
if let CharacterState::BasicBeam(b) = character_state {
|
||||
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_directed(
|
||||
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_directed(
|
||||
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,
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
let mut rng = thread_rng();
|
||||
let (from, to) = (Vec3::<f32>::unit_z(), *ori.look_dir());
|
||||
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);
|
||||
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_directed(
|
||||
self.particles.resize_with(
|
||||
self.particles.len() + 2 * usize::from(beam_tick_count),
|
||||
|| {
|
||||
let phi: f32 = rng.gen_range(0.0..beam.properties.angle);
|
||||
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_directed(
|
||||
beam.properties.duration,
|
||||
time,
|
||||
ParticleMode::FlameThrower,
|
||||
pos.0,
|
||||
pos.0 + random_ori * range,
|
||||
)
|
||||
},
|
||||
);
|
||||
},
|
||||
beam::FrontendSpecifier::HealingBeam => {
|
||||
// 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..beam_tick_count {
|
||||
self.particles.push(Particle::new_directed(
|
||||
beam.properties.duration,
|
||||
time,
|
||||
ParticleMode::FlameThrower,
|
||||
pos.0, /* + random_ori */
|
||||
pos.0 + random_ori * range,
|
||||
)
|
||||
},
|
||||
);
|
||||
time + i as f64 / 1000.0,
|
||||
ParticleMode::HealingBeam,
|
||||
pos.0,
|
||||
pos.0 + *ori.look_dir() * range,
|
||||
));
|
||||
}
|
||||
},
|
||||
beam::FrontendSpecifier::LifestealBeam => {
|
||||
// Emit a light when using lifesteal beam
|
||||
lights.push(Light::new(pos.0, Rgb::new(0.8, 1.0, 0.5), 1.0));
|
||||
for i in 0..beam_tick_count {
|
||||
self.particles.push(Particle::new_directed(
|
||||
beam.properties.duration,
|
||||
time + i as f64 / 1000.0,
|
||||
ParticleMode::LifestealBeam,
|
||||
pos.0,
|
||||
pos.0 + *ori.look_dir() * range,
|
||||
));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user