Add knockback to poise

This commit is contained in:
jiminycrick 2020-12-09 16:32:24 -08:00
parent e3965ae0ab
commit af076aa87f
13 changed files with 94 additions and 39 deletions

View File

@ -612,8 +612,8 @@ impl Body {
pub fn base_poise_dmg(&self) -> u32 {
match self {
Body::Humanoid(_) => 100,
_ => 50,
Body::Humanoid(_) => 5,
_ => 10,
}
}

View File

@ -108,10 +108,6 @@ impl CharacterState {
matches!(self, CharacterState::Sneak | CharacterState::Roll(_))
}
pub fn is_stunned(&self) -> bool {
matches!(self, CharacterState::Stunned { .. } | CharacterState::Staggered { .. })
}
pub fn is_attack(&self) -> bool {
matches!(
self,
@ -155,6 +151,13 @@ impl CharacterState {
matches!(self, CharacterState::Roll(d) if d.static_data.immune_melee)
}
pub fn is_stunned(&self) -> bool {
matches!(
self,
CharacterState::Stunned(_) | CharacterState::Staggered(_)
)
}
/// Compares for shallow equality (does not check internal struct equality)
pub fn same_variant(&self, other: &Self) -> bool {
// Check if state is the same without looking at the inner data

View File

@ -83,6 +83,7 @@ pub enum PoiseSource {
Shockwave,
Falling,
Revive,
Regen,
Other,
}
@ -95,6 +96,7 @@ pub struct Poise {
pub is_stunned: bool,
pub is_dazed: bool,
pub is_knockeddown: bool,
pub regen_rate: f32,
}
impl Default for Poise {
@ -107,6 +109,7 @@ impl Default for Poise {
is_stunned: false,
is_dazed: false,
is_knockeddown: false,
regen_rate: 0.0,
}
}
}

View File

@ -39,6 +39,7 @@ pub enum ServerEvent {
PoiseChange {
entity: EcsEntity,
change: comp::PoiseChange,
kb_dir: Vec3<f32>,
},
Delete(EcsEntity),
Destroy {

View File

@ -170,7 +170,6 @@ impl CharacterBehavior for Data {
.min(self.combo / self.static_data.num_stages)
* self.static_data.stage_data[stage_index].damage_increase;
let poise_damage = self.static_data.stage_data[stage_index].base_poise_damage;
println!("Combo melee poise damage: {:?}", poise_damage);
data.updater.insert(data.entity, Attacking {
effects: vec![(
Some(GroupTarget::OutOfGroup),

View File

@ -6,6 +6,7 @@ use common::{
event::{EventBus, ServerEvent},
resources::{DeltaTime, Time},
uid::{Uid, UidAllocator},
util::Dir,
GroupTarget,
};
use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage};
@ -170,6 +171,7 @@ impl<'a> System<'a> for Sys {
let poise_change = poise_damage
.modify_poise_damage(inventories.get(b), beam_segment.owner);
let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
match target {
Some(GroupTarget::OutOfGroup) => {
server_emitter.emit(ServerEvent::Damage { entity: b, change });
@ -188,6 +190,7 @@ impl<'a> System<'a> for Sys {
server_emitter.emit(ServerEvent::PoiseChange {
entity,
change: poise_change,
kb_dir: *kb_dir,
});
server_emitter.emit(ServerEvent::EnergyChange {
entity,

View File

@ -101,6 +101,9 @@ impl<'a> System<'a> for Sys {
// Check if entity is dodging
let is_dodge = char_state_b_maybe.map_or(false, |c_s| c_s.is_melee_dodge());
// Check if entity is stunned
let is_stunned = char_state_b_maybe.map_or(false, |c_s| c_s.is_stunned());
// Check if it is a hit
if entity != b
&& !health_b.is_dead
@ -123,7 +126,8 @@ impl<'a> System<'a> for Sys {
for (target, damage, poise_change) in attack.effects.iter() {
if let Some(target) = target {
if *target != target_group
|| (!matches!(target, GroupTarget::InGroup) && is_dodge)
|| (!matches!(target, GroupTarget::InGroup)
&& (is_dodge || is_stunned))
{
continue;
}
@ -132,13 +136,7 @@ impl<'a> System<'a> for Sys {
let change = damage.modify_damage(inventories.get(b), Some(*uid));
//let poise_change =
// poise_change.modify_poise_damage(loadouts.get(b), Some(*uid));
println!("poise_change in melee: {:?}", poise_change);
server_emitter.emit(ServerEvent::Damage { entity: b, change });
server_emitter.emit(ServerEvent::PoiseChange {
entity: b,
change: *poise_change,
});
// Apply bleeding buff on melee hits with 10% chance
// TODO: Don't have buff uniformly applied on all melee attacks
if change.amount < 0 && thread_rng().gen::<f32>() < 0.1 {
@ -162,6 +160,12 @@ impl<'a> System<'a> for Sys {
server_emitter.emit(ServerEvent::Knockback { entity: b, impulse });
}
server_emitter.emit(ServerEvent::PoiseChange {
entity: b,
change: *poise_change,
kb_dir: *kb_dir,
});
attack.hit_count += 1;
}
}

View File

@ -128,6 +128,7 @@ impl<'a> System<'a> for Sys {
server_emitter.emit(ServerEvent::PoiseChange {
entity: other_entity,
change: poise_change,
kb_dir: *ori.0,
});
}
},

View File

@ -204,10 +204,6 @@ impl<'a> System<'a> for Sys {
poise_damage.modify_poise_damage(inventories.get(b), Some(owner_uid));
server_emitter.emit(ServerEvent::Damage { entity: b, change });
server_emitter.emit(ServerEvent::PoiseChange {
entity: b,
change: poise_change,
});
shockwave_hit_list.hit_entities.push(*uid_b);
let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
@ -215,6 +211,11 @@ impl<'a> System<'a> for Sys {
if !impulse.is_approx_zero() {
server_emitter.emit(ServerEvent::Knockback { entity: b, impulse });
}
server_emitter.emit(ServerEvent::PoiseChange {
entity: b,
change: poise_change,
kb_dir: *kb_dir,
});
}
}
}

View File

@ -1,7 +1,8 @@
use common::{
comp::{
skills::{GeneralSkill, Skill},
Body, CharacterState, Energy, EnergyChange, EnergySource, Health, Pos, Stats,
Body, CharacterState, Energy, EnergyChange, EnergySource, Health, Poise, PoiseChange,
PoiseSource, Pos, Stats,
},
event::{EventBus, ServerEvent},
metrics::SysMetrics,
@ -14,6 +15,7 @@ use hashbrown::HashSet;
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage};
const ENERGY_REGEN_ACCEL: f32 = 10.0;
//const POISE_REGEN_ACCEL: f32 = 5.0;
/// This system kills players, levels them up, and regenerates energy.
pub struct Sys;
@ -27,6 +29,7 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, CharacterState>,
WriteStorage<'a, Stats>,
WriteStorage<'a, Health>,
WriteStorage<'a, Poise>,
WriteStorage<'a, Energy>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Pos>,
@ -44,6 +47,7 @@ impl<'a> System<'a> for Sys {
character_states,
mut stats,
mut healths,
mut poises,
mut energies,
uids,
positions,
@ -147,9 +151,13 @@ impl<'a> System<'a> for Sys {
}
}
// Update energies
for (character_state, mut energy) in
(&character_states, &mut energies.restrict_mut()).join()
// Update energies and poises
for (character_state, mut energy, mut poise) in (
&character_states,
&mut energies.restrict_mut(),
&mut poises.restrict_mut(),
)
.join()
{
match character_state {
// Accelerate recharging energy.
@ -179,6 +187,23 @@ impl<'a> System<'a> for Sys {
energy.regen_rate =
(energy.regen_rate + ENERGY_REGEN_ACCEL * dt.0).min(100.0);
}
//let res_poise = {
// let poise = poise.get_unchecked();
// poise.current() < poise.maximum()
//};
//if res_poise {
// let mut poise = poise.get_mut_unchecked();
// poise.change_by(PoiseChange {
// amount: (poise.regen_rate * dt.0
// + POISE_REGEN_ACCEL * dt.0.powi(2) / 2.0)
// as i32,
// source: PoiseSource::Regen,
// });
// poise.regen_rate = (poise.regen_rate +
// POISE_REGEN_ACCEL * dt.0).min(100.0);
//}
},
// Ability and glider use does not regen and sets the rate back to zero.
CharacterState::Glide { .. }
@ -217,7 +242,10 @@ impl<'a> System<'a> for Sys {
CharacterState::Roll { .. }
| CharacterState::Climb { .. }
| CharacterState::Stunned { .. }
| CharacterState::Staggered { .. } => {},
| CharacterState::Staggered { .. } => {
let poise = poise.get_unchecked();
println!("Poise: {:?}", poise.current());
},
}
}
sys_metrics.stats_ns.store(

View File

@ -36,7 +36,12 @@ use std::time::Duration;
use tracing::error;
use vek::Vec3;
pub fn handle_poise(server: &Server, entity: EcsEntity, change: PoiseChange) {
pub fn handle_poise(
server: &Server,
entity: EcsEntity,
change: PoiseChange,
knockback_dir: Vec3<f32>,
) {
let ecs = &server.state.ecs();
if let Some(poise) = ecs.write_storage::<Poise>().get_mut(entity) {
poise.change_by(change);
@ -57,7 +62,7 @@ pub fn handle_poise(server: &Server, entity: EcsEntity, change: PoiseChange) {
static_data: common::states::stunned::StaticData {
buildup_duration: Duration::from_millis(250),
recover_duration: Duration::from_millis(250),
knockback: Knockback::Away(0.0),
knockback: Knockback::Away(20.0),
},
timer: Duration::default(),
stage_section: common::states::utils::StageSection::Buildup,
@ -71,47 +76,50 @@ pub fn handle_poise(server: &Server, entity: EcsEntity, change: PoiseChange) {
entity,
comp::CharacterState::Stunned(common::states::stunned::Data {
static_data: common::states::stunned::StaticData {
buildup_duration: Duration::from_millis(250),
recover_duration: Duration::from_millis(250),
knockback: Knockback::Away(0.0),
buildup_duration: Duration::from_millis(500),
recover_duration: Duration::from_millis(500),
knockback: Knockback::Away(40.0),
},
timer: Duration::default(),
stage_section: common::states::utils::StageSection::Buildup,
was_wielded,
}),
);
handle_knockback(server, entity, 50.0 * knockback_dir);
},
PoiseState::Dazed => {
poise.reset();
let _ = ecs.write_storage::<comp::CharacterState>().insert(
entity,
comp::CharacterState::Stunned(common::states::stunned::Data {
static_data: common::states::stunned::StaticData {
buildup_duration: Duration::from_millis(250),
recover_duration: Duration::from_millis(250),
knockback: Knockback::Away(0.0),
comp::CharacterState::Staggered(common::states::staggered::Data {
static_data: common::states::staggered::StaticData {
buildup_duration: Duration::from_millis(1000),
recover_duration: Duration::from_millis(1000),
knockback: Knockback::Away(50.0),
},
timer: Duration::default(),
stage_section: common::states::utils::StageSection::Buildup,
was_wielded,
}),
);
handle_knockback(server, entity, 50.0 * knockback_dir);
},
PoiseState::KnockedDown => {
poise.reset();
let _ = ecs.write_storage::<comp::CharacterState>().insert(
entity,
comp::CharacterState::Stunned(common::states::stunned::Data {
static_data: common::states::stunned::StaticData {
buildup_duration: Duration::from_millis(250),
comp::CharacterState::Staggered(common::states::staggered::Data {
static_data: common::states::staggered::StaticData {
buildup_duration: Duration::from_millis(5000),
recover_duration: Duration::from_millis(250),
knockback: Knockback::Away(0.0),
knockback: Knockback::Away(200.0),
},
timer: Duration::default(),
stage_section: common::states::utils::StageSection::Buildup,
was_wielded,
}),
);
handle_knockback(server, entity, 100.0 * knockback_dir);
},
}
}

View File

@ -83,7 +83,11 @@ impl Server {
handle_knockback(&self, entity, impulse)
},
ServerEvent::Damage { entity, change } => handle_damage(&self, entity, change),
ServerEvent::PoiseChange { entity, change } => handle_poise(&self, entity, change),
ServerEvent::PoiseChange {
entity,
change,
kb_dir,
} => handle_poise(&self, entity, change, kb_dir),
ServerEvent::Delete(entity) => handle_delete(self, entity),
ServerEvent::Destroy { entity, cause } => handle_destroy(self, entity, cause),
ServerEvent::InventoryManip(entity, manip) => handle_inventory(self, entity, manip),

View File

@ -55,7 +55,7 @@ impl<'a> System<'a> for Sys {
value: 500.0,
}),
Effect::Poise(PoiseChange {
amount: -60,
amount: -80,
source: PoiseSource::Explosion,
}),
]),