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 ENERGY_NATURE = 14;
const int FLAMETHROWER = 15;
const int FIRE_SHOCKWAVE = 16;
// meters per second squared (acceleration)
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),
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 {
attr = Attr(
linear_motion(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -355,6 +355,14 @@ pub fn handle_interrupt(data: &JoinData, update: &mut StateUpdate) {
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
/// used to control aspects of animation code, as well as logic within the
/// character states.
@ -368,3 +376,10 @@ pub enum StageSection {
Shoot,
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 energy_mut
.try_change_by(
-(beam_segment.energy_drain as i32), // Stamina use
-(beam_segment.energy_cost as i32), // Stamina use
EnergySource::Ability,
)
.is_ok()

View File

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

View File

@ -544,24 +544,23 @@ impl ParticleMgr {
let theta = ori.0.y.atan2(ori.0.x);
let dtheta = radians / distance;
if shockwave.properties.requires_ground {
// 1 / 3 the size of terrain voxel
let scale = 1.0 / 3.0;
let heartbeats = self.scheduler.heartbeats(Duration::from_millis(1));
let scaled_speed = shockwave.properties.speed * scale;
for heartbeat in 0..heartbeats {
if shockwave.properties.requires_ground {
// 1 / 3 the size of terrain voxel
let scale = 1.0 / 3.0;
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);
let scaled_speed = shockwave.properties.speed * scale;
for heartbeat in 0..heartbeats {
let sub_tick_interpolation = scaled_speed * 1000.0 * heartbeat as f32;
let distance =
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) {
let arc_position = theta - radians / 2.0 + dtheta * d as f32 * scale;
@ -577,8 +576,21 @@ impl ParticleMgr {
position_snapped,
));
}
} 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,
));
}
}
} else {
}
}
}