From f24433c8cfa37f35ecf4c33cbf74811d3097429b Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 27 Feb 2021 14:55:06 -0500 Subject: [PATCH] Added combo component --- common/net/src/msg/ecs_packet.rs | 5 +++ common/src/combat.rs | 24 +++++++++++++++ common/src/comp/combo.rs | 39 ++++++++++++++++++++++++ common/src/comp/mod.rs | 2 ++ common/src/event.rs | 4 +++ common/src/states/combo_melee.rs | 3 +- common/sys/src/state.rs | 1 + common/sys/src/stats.rs | 17 +++++++++-- server/src/events/entity_manipulation.rs | 13 ++++++++ server/src/events/mod.rs | 8 +++-- server/src/state_ext.rs | 2 ++ 11 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 common/src/comp/combo.rs diff --git a/common/net/src/msg/ecs_packet.rs b/common/net/src/msg/ecs_packet.rs index 599115dcd1..1ee77e127d 100644 --- a/common/net/src/msg/ecs_packet.rs +++ b/common/net/src/msg/ecs_packet.rs @@ -17,6 +17,7 @@ sum_type! { Buffs(comp::Buffs), Auras(comp::Auras), Energy(comp::Energy), + Combo(comp::Combo), Health(comp::Health), Poise(comp::Poise), LightEmitter(comp::LightEmitter), @@ -50,6 +51,7 @@ sum_type! { Buffs(PhantomData), Auras(PhantomData), Energy(PhantomData), + Combo(PhantomData), Health(PhantomData), Poise(PhantomData), LightEmitter(PhantomData), @@ -83,6 +85,7 @@ impl sync::CompPacket for EcsCompPacket { EcsCompPacket::Buffs(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Auras(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Energy(comp) => sync::handle_insert(comp, entity, world), + EcsCompPacket::Combo(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Health(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Poise(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::LightEmitter(comp) => sync::handle_insert(comp, entity, world), @@ -114,6 +117,7 @@ impl sync::CompPacket for EcsCompPacket { EcsCompPacket::Buffs(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Auras(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Energy(comp) => sync::handle_modify(comp, entity, world), + EcsCompPacket::Combo(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Health(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Poise(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::LightEmitter(comp) => sync::handle_modify(comp, entity, world), @@ -145,6 +149,7 @@ impl sync::CompPacket for EcsCompPacket { EcsCompPhantom::Buffs(_) => sync::handle_remove::(entity, world), EcsCompPhantom::Auras(_) => sync::handle_remove::(entity, world), EcsCompPhantom::Energy(_) => sync::handle_remove::(entity, world), + EcsCompPhantom::Combo(_) => sync::handle_remove::(entity, world), EcsCompPhantom::Health(_) => sync::handle_remove::(entity, world), EcsCompPhantom::Poise(_) => sync::handle_remove::(entity, world), EcsCompPhantom::LightEmitter(_) => { diff --git a/common/src/combat.rs b/common/src/combat.rs index 5580e398dc..803b009693 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -86,6 +86,13 @@ impl Attack { self } + pub fn with_combo_increment(self) -> Self { + self.with_effect( + AttackEffect::new(None, CombatEffect::Combo(1)) + .with_requirement(CombatRequirement::AnyDamage), + ) + } + pub fn effects(&self) -> impl Iterator { self.effects.iter() } #[allow(clippy::too_many_arguments)] @@ -195,6 +202,14 @@ impl Attack { }); } }, + CombatEffect::Combo(c) => { + if let Some(attacker_entity) = attacker_info.map(|a| a.entity) { + emit(ServerEvent::ComboChange { + entity: attacker_entity, + change: *c, + }); + } + }, } } } @@ -303,6 +318,14 @@ impl Attack { }); } }, + CombatEffect::Combo(c) => { + if let Some(attacker_entity) = attacker_info.map(|a| a.entity) { + emit(ServerEvent::ComboChange { + entity: attacker_entity, + change: c, + }); + } + }, } } } @@ -368,6 +391,7 @@ pub enum CombatEffect { EnergyReward(f32), Lifesteal(f32), Poise(f32), + Combo(i32), } #[cfg(not(target_arch = "wasm32"))] diff --git a/common/src/comp/combo.rs b/common/src/comp/combo.rs new file mode 100644 index 0000000000..a532d25bb3 --- /dev/null +++ b/common/src/comp/combo.rs @@ -0,0 +1,39 @@ +use serde::{Deserialize, Serialize}; +use specs::{Component, DerefFlaggedStorage}; +use specs_idvs::IdvStorage; + +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +pub struct Combo { + counter: u32, + last_increase: f64, +} + +impl Default for Combo { + fn default() -> Self { + Self { + counter: 0, + last_increase: 0.0, + } + } +} + +impl Combo { + pub fn counter(&self) -> u32 { self.counter } + + pub fn last_increase(&self) -> f64 { self.last_increase } + + pub fn reset(&mut self) { self.counter = 0; } + + pub fn increase_by(&mut self, amount: u32, time: f64) { + self.counter = self.counter.saturating_add(amount); + self.last_increase = time; + } + + pub fn decrease_by(&mut self, amount: u32) { + self.counter = self.counter.saturating_sub(amount); + } +} + +impl Component for Combo { + type Storage = DerefFlaggedStorage>; +} diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 38d1694b52..8e342cde4e 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -8,6 +8,7 @@ pub mod buff; #[cfg(not(target_arch = "wasm32"))] mod character_state; #[cfg(not(target_arch = "wasm32"))] pub mod chat; +pub mod combo; #[cfg(not(target_arch = "wasm32"))] mod controller; #[cfg(not(target_arch = "wasm32"))] mod energy; @@ -58,6 +59,7 @@ pub use self::{ chat::{ ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg, }, + combo::Combo, controller::{ Climb, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, Input, InventoryManip, LoadoutManip, MountState, Mounting, SlotManip, diff --git a/common/src/event.rs b/common/src/event.rs index 0a73cfa947..ecf2f784ea 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -143,6 +143,10 @@ pub enum ServerEvent { entity: EcsEntity, change: comp::EnergyChange, }, + ComboChange { + entity: EcsEntity, + change: i32, + }, } pub struct EventBus { diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index a16bf7edac..55a97e52a3 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -214,7 +214,8 @@ impl CharacterBehavior for Data { .with_crit(0.5, 1.3) .with_effect(energy) .with_effect(poise) - .with_effect(knockback); + .with_effect(knockback) + .with_combo_increment(); data.updater.insert(data.entity, Melee { attack, diff --git a/common/sys/src/state.rs b/common/sys/src/state.rs index 80d00654e2..cdd3036b1e 100644 --- a/common/sys/src/state.rs +++ b/common/sys/src/state.rs @@ -127,6 +127,7 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); + ecs.register::(); ecs.register::(); ecs.register::(); ecs.register::(); diff --git a/common/sys/src/stats.rs b/common/sys/src/stats.rs index 51f85e6184..93f2e20302 100644 --- a/common/sys/src/stats.rs +++ b/common/sys/src/stats.rs @@ -1,13 +1,13 @@ use common::{ comp::{ skills::{GeneralSkill, Skill}, - Body, CharacterState, Energy, EnergyChange, EnergySource, Health, Poise, PoiseChange, - PoiseSource, Pos, Stats, + Body, CharacterState, Combo, Energy, EnergyChange, EnergySource, Health, Poise, + PoiseChange, PoiseSource, Pos, Stats, }, event::{EventBus, ServerEvent}, metrics::SysMetrics, outcome::Outcome, - resources::DeltaTime, + resources::{DeltaTime, Time}, span, uid::Uid, }; @@ -20,11 +20,13 @@ use vek::Vec3; const ENERGY_REGEN_ACCEL: f32 = 10.0; const POISE_REGEN_ACCEL: f32 = 2.0; +const COMBO_DECAY_START: f64 = 10.0; // seconds #[derive(SystemData)] pub struct ReadData<'a> { entities: Entities<'a>, dt: Read<'a, DeltaTime>, + time: Read<'a, Time>, server_bus: Read<'a, EventBus>, metrics: ReadExpect<'a, SysMetrics>, positions: ReadStorage<'a, Pos>, @@ -43,6 +45,7 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Health>, WriteStorage<'a, Poise>, WriteStorage<'a, Energy>, + WriteStorage<'a, Combo>, Write<'a, Vec>, ); @@ -54,6 +57,7 @@ impl<'a> System<'a> for Sys { mut healths, mut poises, mut energies, + mut combos, mut outcomes, ): Self::SystemData, ) { @@ -256,6 +260,13 @@ impl<'a> System<'a> for Sys { } } + // Decay combo + for (_, mut combo) in (&read_data.entities, &mut combos).join() { + if combo.counter() > 0 && read_data.time.0 - combo.last_increase() > COMBO_DECAY_START { + combo.reset(); + } + } + read_data.metrics.stats_ns.store( start_time.elapsed().as_nanos() as u64, std::sync::atomic::Ordering::Relaxed, diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index c3aa3a8298..cb4762e5a9 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -20,6 +20,7 @@ use common::{ event::{EventBus, ServerEvent}, lottery::Lottery, outcome::Outcome, + resources::Time, rtsim::RtSimEntity, terrain::{Block, TerrainGrid}, uid::{Uid, UidAllocator}, @@ -880,3 +881,15 @@ fn handle_exp_gain( exp: exp_reward as i32, }); } + +pub fn handle_combo_change(server: &Server, entity: EcsEntity, change: i32) { + let ecs = &server.state.ecs(); + if let Some(mut combo) = ecs.write_storage::().get_mut(entity) { + if change > 0 { + let time = ecs.read_resource::