mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Tweaked particles. Added skill icons.
This commit is contained in:
parent
8b9202710f
commit
6b23af6e0b
BIN
assets/voxygen/element/icons/heal_bomb.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/heal_bomb.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -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(
|
||||
|
@ -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<Body> 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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
]
|
||||
|
@ -14,6 +14,7 @@ pub enum Outcome {
|
||||
pos: Vec3<f32>,
|
||||
power: f32,
|
||||
reagent: Option<Reagent>, // How can we better define this?
|
||||
percent_damage: f32,
|
||||
},
|
||||
ProjectileShot {
|
||||
pos: Vec3<f32>,
|
||||
|
@ -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::<Attacking>(data.entity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
update
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -462,6 +462,7 @@ pub fn handle_explosion(
|
||||
pos,
|
||||
power,
|
||||
reagent,
|
||||
percent_damage,
|
||||
});
|
||||
let owner_entity = owner.and_then(|uid| {
|
||||
ecs.read_resource::<UidAllocator>()
|
||||
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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() {
|
||||
|
@ -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<f32>,
|
||||
inst_pos2: Vec3<f32>,
|
||||
) -> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -390,6 +390,7 @@ impl Scene {
|
||||
pos,
|
||||
power,
|
||||
reagent,
|
||||
..
|
||||
} => self.event_lights.push(EventLight {
|
||||
light: Light::new(
|
||||
*pos,
|
||||
|
@ -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::<f32>::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::<f32>::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::<f32>::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<f32>,
|
||||
pos2: Vec3<f32>,
|
||||
) -> Self {
|
||||
Particle {
|
||||
alive_until: time + lifespan.as_secs_f64(),
|
||||
instance: ParticleInstance::new_beam(time, mode, pos1, pos2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user