Added particles for fire shockwave. Added ability key enum so held abilities could differentiate what button they should check. Modified energy fields on basic beam so it could drain energy every second.

This commit is contained in:
Sam 2020-10-06 21:32:57 -05:00
parent cbb72363af
commit 7ef73f5981
12 changed files with 89 additions and 32 deletions

View File

@ -52,6 +52,7 @@ const int GROUND_SHOCKWAVE = 12;
const int HEALING_BEAM = 13; const int HEALING_BEAM = 13;
const int ENERGY_NATURE = 14; const int ENERGY_NATURE = 14;
const int FLAMETHROWER = 15; const int FLAMETHROWER = 15;
const int FIRE_SHOCKWAVE = 16;
// meters per second squared (acceleration) // meters per second squared (acceleration)
const float earth_gravity = 9.807; const float earth_gravity = 9.807;
@ -294,6 +295,13 @@ void main() {
vec4(1, 0.6 + rand5 * 0.3 - 0.6 * lifetime / inst_lifespan, 0, 0.8 - 0.6 * lifetime / inst_lifespan), vec4(1, 0.6 + rand5 * 0.3 - 0.6 * lifetime / inst_lifespan, 0, 0.8 - 0.6 * lifetime / inst_lifespan),
spin_in_axis(vec3(rand6, rand7, rand8), lifetime / inst_lifespan * 10 + 3 * rand9) spin_in_axis(vec3(rand6, rand7, rand8), lifetime / inst_lifespan * 10 + 3 * rand9)
); );
} else if (inst_mode == FIRE_SHOCKWAVE) {
attr = Attr(
vec3(rand0, rand1, lifetime * 10 + rand2),
vec3(1.6 + rand3 * 1.5 + 10 * (lifetime + inst_lifespan)),
vec4(1, 0.6 + rand7 * 0.3 - 5 * inst_lifespan + 2 * lifetime, 0, 0.8 - 3.5 * inst_lifespan),
spin_in_axis(vec3(rand3, rand4, rand5), rand6)
);
} else { } else {
attr = Attr( attr = Attr(
linear_motion( linear_motion(

View File

@ -3,7 +3,10 @@ use crate::{
item::{armor::Protection, Item, ItemKind}, item::{armor::Protection, Item, ItemKind},
Body, CharacterState, EnergySource, Gravity, LightEmitter, Projectile, StateUpdate, Body, CharacterState, EnergySource, Gravity, LightEmitter, Projectile, StateUpdate,
}, },
states::{utils::StageSection, *}, states::{
utils::{AbilityKey, StageSection},
*,
},
sys::character_behavior::JoinData, sys::character_behavior::JoinData,
}; };
use arraygen::Arraygen; use arraygen::Arraygen;
@ -187,7 +190,6 @@ pub enum CharacterAbility {
requires_ground: bool, requires_ground: bool,
}, },
BasicBeam { BasicBeam {
energy_cost: u32,
buildup_duration: Duration, buildup_duration: Duration,
recover_duration: Duration, recover_duration: Duration,
beam_duration: Duration, beam_duration: Duration,
@ -198,7 +200,9 @@ pub enum CharacterAbility {
max_angle: f32, max_angle: f32,
lifesteal_eff: f32, lifesteal_eff: f32,
energy_regen: u32, energy_regen: u32,
energy_cost: u32,
energy_drain: u32, energy_drain: u32,
ability_key: AbilityKey,
}, },
} }
@ -252,9 +256,9 @@ impl CharacterAbility {
.energy .energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability) .try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(), .is_ok(),
CharacterAbility::BasicBeam { energy_cost, .. } => update CharacterAbility::BasicBeam { energy_drain, .. } => update
.energy .energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability) .try_change_by(-(*energy_drain as i32), EnergySource::Ability)
.is_ok(), .is_ok(),
_ => true, _ => true,
} }
@ -640,7 +644,6 @@ impl From<&CharacterAbility> for CharacterState {
requires_ground: *requires_ground, requires_ground: *requires_ground,
}), }),
CharacterAbility::BasicBeam { CharacterAbility::BasicBeam {
energy_cost: _,
buildup_duration, buildup_duration,
recover_duration, recover_duration,
beam_duration, beam_duration,
@ -651,7 +654,9 @@ impl From<&CharacterAbility> for CharacterState {
max_angle, max_angle,
lifesteal_eff, lifesteal_eff,
energy_regen, energy_regen,
energy_cost,
energy_drain, energy_drain,
ability_key,
} => CharacterState::BasicBeam(basic_beam::Data { } => CharacterState::BasicBeam(basic_beam::Data {
static_data: basic_beam::StaticData { static_data: basic_beam::StaticData {
buildup_duration: *buildup_duration, buildup_duration: *buildup_duration,
@ -664,7 +669,9 @@ impl From<&CharacterAbility> for CharacterState {
max_angle: *max_angle, max_angle: *max_angle,
lifesteal_eff: *lifesteal_eff, lifesteal_eff: *lifesteal_eff,
energy_regen: *energy_regen, energy_regen: *energy_regen,
energy_cost: *energy_cost,
energy_drain: *energy_drain, energy_drain: *energy_drain,
ability_key: *ability_key,
}, },
timer: Duration::default(), timer: Duration::default(),
stage_section: StageSection::Buildup, stage_section: StageSection::Buildup,

View File

@ -12,7 +12,7 @@ pub struct Properties {
pub heal: u32, pub heal: u32,
pub lifesteal_eff: f32, pub lifesteal_eff: f32,
pub energy_regen: u32, pub energy_regen: u32,
pub energy_drain: u32, pub energy_cost: u32,
pub duration: Duration, pub duration: Duration,
pub owner: Option<Uid>, pub owner: Option<Uid>,
} }

View File

@ -6,7 +6,7 @@ use crate::{
body::object, projectile, Body, CharacterAbility, Explosion, Gravity, LightEmitter, body::object, projectile, Body, CharacterAbility, Explosion, Gravity, LightEmitter,
Projectile, Projectile,
}, },
states::combo_melee, states::{combo_melee, utils::AbilityKey},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
@ -365,7 +365,6 @@ impl Tool {
}], }],
Sceptre(_) => vec![ Sceptre(_) => vec![
BasicBeam { BasicBeam {
energy_cost: 0,
buildup_duration: Duration::from_millis(250), buildup_duration: Duration::from_millis(250),
recover_duration: Duration::from_millis(250), recover_duration: Duration::from_millis(250),
beam_duration: Duration::from_secs(1), beam_duration: Duration::from_secs(1),
@ -376,7 +375,9 @@ impl Tool {
max_angle: 1.0, max_angle: 1.0,
lifesteal_eff: 0.20, lifesteal_eff: 0.20,
energy_regen: 50, energy_regen: 50,
energy_drain: 100, energy_cost: 100,
energy_drain: 0,
ability_key: AbilityKey::Mouse1,
}, },
BasicRanged { BasicRanged {
energy_cost: 800, energy_cost: 800,
@ -461,7 +462,6 @@ impl Tool {
projectile_speed: 60.0, projectile_speed: 60.0,
}, },
BasicBeam { BasicBeam {
energy_cost: 0,
buildup_duration: Duration::from_millis(250), buildup_duration: Duration::from_millis(250),
recover_duration: Duration::from_millis(250), recover_duration: Duration::from_millis(250),
beam_duration: Duration::from_millis(500), beam_duration: Duration::from_millis(500),
@ -471,8 +471,10 @@ impl Tool {
range: 15.0, range: 15.0,
max_angle: 22.5, max_angle: 22.5,
lifesteal_eff: 0.0, lifesteal_eff: 0.0,
energy_regen: 50, energy_regen: 0,
energy_cost: 0,
energy_drain: 0, energy_drain: 0,
ability_key: AbilityKey::Mouse2,
}, },
Shockwave { Shockwave {
energy_cost: 0, energy_cost: 0,

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
comp::{beam, humanoid, Body, CharacterState, Ori, Pos, StateUpdate}, comp::{beam, humanoid, Body, CharacterState, EnergySource, Ori, Pos, StateUpdate},
event::ServerEvent, event::ServerEvent,
states::utils::{StageSection, *}, states::utils::*,
sync::Uid, sync::Uid,
sys::character_behavior::{CharacterBehavior, JoinData}, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
@ -34,7 +34,11 @@ pub struct StaticData {
/// Energy regened per second for damage ticks /// Energy regened per second for damage ticks
pub energy_regen: u32, pub energy_regen: u32,
/// Energy consumed per second for heal ticks /// Energy consumed per second for heal ticks
pub energy_cost: u32,
/// Energy drained per
pub energy_drain: u32, pub energy_drain: u32,
/// What key is used to press ability
pub ability_key: AbilityKey,
} }
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -101,15 +105,17 @@ impl CharacterBehavior for Data {
} }
}, },
StageSection::Cast => { StageSection::Cast => {
if data.inputs.primary.is_pressed() { if ability_key_is_pressed(data, self.static_data.ability_key)
&& (self.static_data.energy_drain == 0 || update.energy.current() > 0)
{
let damage = let damage =
(self.static_data.base_dps as f32 / self.static_data.tick_rate) as u32; (self.static_data.base_dps as f32 / self.static_data.tick_rate) as u32;
let heal = let heal =
(self.static_data.base_hps as f32 / self.static_data.tick_rate) as u32; (self.static_data.base_hps as f32 / self.static_data.tick_rate) as u32;
let energy_regen = let energy_regen =
(self.static_data.energy_regen as f32 / self.static_data.tick_rate) as u32; (self.static_data.energy_regen as f32 / self.static_data.tick_rate) as u32;
let energy_drain = let energy_cost =
(self.static_data.energy_drain as f32 / self.static_data.tick_rate) as u32; (self.static_data.energy_cost as f32 / self.static_data.tick_rate) as u32;
let speed = let speed =
self.static_data.range / self.static_data.beam_duration.as_secs_f32(); self.static_data.range / self.static_data.beam_duration.as_secs_f32();
let properties = beam::Properties { let properties = beam::Properties {
@ -119,7 +125,7 @@ impl CharacterBehavior for Data {
heal, heal,
lifesteal_eff: self.static_data.lifesteal_eff, lifesteal_eff: self.static_data.lifesteal_eff,
energy_regen, energy_regen,
energy_drain, energy_cost,
duration: self.static_data.beam_duration, duration: self.static_data.beam_duration,
owner: Some(*data.uid), owner: Some(*data.uid),
}; };
@ -137,6 +143,12 @@ impl CharacterBehavior for Data {
particle_ori: Some(*data.inputs.look_dir), particle_ori: Some(*data.inputs.look_dir),
offset: self.offset, offset: self.offset,
}); });
// Consumes energy if there's enough left and ability key is held down
update.energy.change_by(
-(self.static_data.energy_drain as f32 * data.dt.0) as i32,
EnergySource::Ability,
);
} else { } else {
update.character = CharacterState::BasicBeam(Data { update.character = CharacterState::BasicBeam(Data {
static_data: self.static_data, static_data: self.static_data,

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate}, comp::{Attacking, CharacterState, EnergySource, StateUpdate},
states::utils::{StageSection, *}, states::utils::*,
sys::character_behavior::{CharacterBehavior, JoinData}, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate}, comp::{Attacking, CharacterState, EnergySource, StateUpdate},
states::utils::{StageSection, *}, states::utils::*,
sys::character_behavior::{CharacterBehavior, JoinData}, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate}, comp::{Attacking, CharacterState, EnergySource, StateUpdate},
states::utils::{StageSection, *}, states::utils::*,
sys::character_behavior::{CharacterBehavior, JoinData}, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@ -355,6 +355,14 @@ pub fn handle_interrupt(data: &JoinData, update: &mut StateUpdate) {
handle_dodge_input(data, update); handle_dodge_input(data, update);
} }
pub fn ability_key_is_pressed(data: &JoinData, ability_key: AbilityKey) -> bool {
match ability_key {
AbilityKey::Mouse1 => data.inputs.primary.is_pressed(),
AbilityKey::Mouse2 => data.inputs.secondary.is_pressed(),
AbilityKey::Skill1 => data.inputs.ability3.is_pressed(),
}
}
/// Determines what portion a state is in. Used in all attacks (eventually). Is /// Determines what portion a state is in. Used in all attacks (eventually). Is
/// used to control aspects of animation code, as well as logic within the /// used to control aspects of animation code, as well as logic within the
/// character states. /// character states.
@ -368,3 +376,10 @@ pub enum StageSection {
Shoot, Shoot,
Movement, Movement,
} }
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum AbilityKey {
Mouse1,
Mouse2,
Skill1,
}

View File

@ -232,7 +232,7 @@ impl<'a> System<'a> for Sys {
if let Some(energy_mut) = beam_owner.and_then(|o| energies.get_mut(o)) { if let Some(energy_mut) = beam_owner.and_then(|o| energies.get_mut(o)) {
if energy_mut if energy_mut
.try_change_by( .try_change_by(
-(beam_segment.energy_drain as i32), // Stamina use -(beam_segment.energy_cost as i32), // Stamina use
EnergySource::Ability, EnergySource::Ability,
) )
.is_ok() .is_ok()

View File

@ -112,6 +112,7 @@ pub enum ParticleMode {
HealingBeam = 13, HealingBeam = 13,
EnergyNature = 14, EnergyNature = 14,
FlameThrower = 15, FlameThrower = 15,
FireShockwave = 16,
} }
impl ParticleMode { impl ParticleMode {

View File

@ -544,24 +544,23 @@ impl ParticleMgr {
let theta = ori.0.y.atan2(ori.0.x); let theta = ori.0.y.atan2(ori.0.x);
let dtheta = radians / distance; let dtheta = radians / distance;
let heartbeats = self.scheduler.heartbeats(Duration::from_millis(1));
for heartbeat in 0..heartbeats {
if shockwave.properties.requires_ground { if shockwave.properties.requires_ground {
// 1 / 3 the size of terrain voxel // 1 / 3 the size of terrain voxel
let scale = 1.0 / 3.0; let scale = 1.0 / 3.0;
let scaled_speed = shockwave.properties.speed * scale; let scaled_speed = shockwave.properties.speed * scale;
let heartbeats = self
.scheduler
.heartbeats(Duration::from_millis(scaled_speed as u64));
let new_particle_count = distance / scale * heartbeats as f32;
self.particles.reserve(new_particle_count as usize);
for heartbeat in 0..heartbeats {
let sub_tick_interpolation = scaled_speed * 1000.0 * heartbeat as f32; let sub_tick_interpolation = scaled_speed * 1000.0 * heartbeat as f32;
let distance = let distance =
shockwave.properties.speed * (elapsed as f32 - sub_tick_interpolation); shockwave.properties.speed * (elapsed as f32 - sub_tick_interpolation);
let new_particle_count = distance / scale as f32;
self.particles.reserve(new_particle_count as usize);
for d in 0..((distance / scale) as i32) { for d in 0..((distance / scale) as i32) {
let arc_position = theta - radians / 2.0 + dtheta * d as f32 * scale; let arc_position = theta - radians / 2.0 + dtheta * d as f32 * scale;
@ -577,8 +576,21 @@ impl ParticleMgr {
position_snapped, position_snapped,
)); ));
} }
}
} else { } else {
for d in 0..10 * distance as i32 {
let arc_position = theta - radians / 2.0 + dtheta * d as f32 / 10.0;
let position = pos.0
+ distance * Vec3::new(arc_position.cos(), arc_position.sin(), 0.0);
self.particles.push(Particle::new(
Duration::from_secs_f32(distance / 50.0),
time,
ParticleMode::FireShockwave,
position,
));
}
}
} }
} }
} }