From 125de0b46e5b50da81f052df25a6aea93119ef1f Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 30 Sep 2020 20:35:57 -0500 Subject: [PATCH] Creatures and playrs now have buffs component, buffs that expire now only end their particular buff instead of every buff with the same type. --- common/src/comp/buff.rs | 8 +++---- common/src/sys/buff.rs | 30 ++++++++++++++---------- common/src/sys/combat.rs | 10 ++++---- server/src/events/entity_manipulation.rs | 9 +++---- server/src/events/mod.rs | 9 +++---- server/src/state_ext.rs | 2 ++ 6 files changed, 36 insertions(+), 32 deletions(-) diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index 5505e61f17..dcd9af6347 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -44,7 +44,7 @@ pub enum BuffCategoryId { #[derive(Clone, Debug, Serialize, Deserialize)] pub enum BuffEffect { /// Periodically damages or heals entity - RepeatedHealthChange { rate: f32, accumulated: f32 }, + HealthChangeOverTime { rate: f32, accumulated: f32 }, /// Changes name on_add/on_remove NameChange { prefix: String }, } @@ -104,9 +104,9 @@ pub enum BuffSource { /// Component holding all de/buffs that gets resolved each tick. /// On each tick, remaining time of buffs get lowered and /// buff effect of each buff is applied or not, depending on the `BuffEffect` -/// (specs system will decide based on `BuffEffect`, to simplify implementation). -/// TODO: Something like `once` flag for `Buff` to remove the dependence on -/// `BuffEffect` enum? +/// (specs system will decide based on `BuffEffect`, to simplify +/// implementation). TODO: Something like `once` flag for `Buff` to remove the +/// dependence on `BuffEffect` enum? /// /// In case of one-time buffs, buff effects will be applied on addition /// and undone on removal of the buff (by the specs system). diff --git a/common/src/sys/buff.rs b/common/src/sys/buff.rs index 987dd7b269..047f18d1b4 100644 --- a/common/src/sys/buff.rs +++ b/common/src/sys/buff.rs @@ -23,13 +23,13 @@ impl<'a> System<'a> for Sys { fn run(&mut self, (entities, dt, mut stats, mut buffs): Self::SystemData) { for (entity, mut buffs) in (&entities, &mut buffs.restrict_mut()).join() { let buff_comp = buffs.get_mut_unchecked(); - let mut buffs_for_removal = Vec::new(); + let mut buff_indices_for_removal = Vec::new(); // Tick all de/buffs on a Buffs component. - for active_buff in &mut buff_comp.buffs { + for i in 0..buff_comp.buffs.len() { // First, tick the buff and subtract delta from it // and return how much "real" time the buff took (for tick independence). // TODO: handle delta for "indefinite" buffs, i.e. time since they got removed. - let buff_delta = if let Some(remaining_time) = &mut active_buff.time { + let buff_delta = if let Some(remaining_time) = &mut buff_comp.buffs[i].time { let pre_tick = remaining_time.as_secs_f32(); let new_duration = remaining_time.checked_sub(Duration::from_secs_f32(dt.0)); let post_tick = if let Some(dur) = new_duration { @@ -38,9 +38,8 @@ impl<'a> System<'a> for Sys { dur.as_secs_f32() } else { // The buff has expired. - // Mark it for removal. - // TODO: This removes by ID! better method required - buffs_for_removal.push(active_buff.id.clone()); + // Remove it. + buff_indices_for_removal.push(i); 0.0 }; pre_tick - post_tick @@ -52,10 +51,10 @@ impl<'a> System<'a> for Sys { }; // Now, execute the buff, based on it's delta - for effect in &mut active_buff.effects { + for effect in &mut buff_comp.buffs[i].effects { match effect { // Only add an effect here if it is continuous or it is not immediate - BuffEffect::RepeatedHealthChange { rate, accumulated } => { + BuffEffect::HealthChangeOverTime { rate, accumulated } => { *accumulated += *rate * buff_delta; // Apply only 0.5 or higher damage if accumulated.abs() > 5.0 { @@ -73,11 +72,16 @@ impl<'a> System<'a> for Sys { }; } } - // Truly mark expired buffs for removal. - // TODO: Review this, as it is ugly. - /*for to_remove in buffs_for_removal { - buff_comp.remove_buff_by_id(to_remove); - }*/ + // Remove buffs that have expired. + // Since buffs are added into this vec as it iterates up through the list, it + // will be in order of increasing values. Therefore to avoid + // removing the incorrect buff, removal will start from the greatest index + // value, which is the last in this vec. + while !buff_indices_for_removal.is_empty() { + if let Some(i) = buff_indices_for_removal.pop() { + buff_comp.buffs.remove(i); + } + } } } } diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index c3359856ad..9945f2bc19 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -1,7 +1,7 @@ use crate::{ comp::{ - buff, group, Attacking, Body, CharacterState, Damage, DamageSource, HealthChange, HealthSource, - Loadout, Ori, Pos, Scale, Stats, + buff, group, Attacking, Body, CharacterState, Damage, DamageSource, HealthChange, + HealthSource, Loadout, Ori, Pos, Scale, Stats, }, event::{EventBus, LocalEvent, ServerEvent}, metrics::SysMetrics, @@ -158,9 +158,9 @@ impl<'a> System<'a> for Sys { id: buff::BuffId::Bleeding, cat_ids: vec![buff::BuffCategoryId::Physical], time: Some(Duration::from_millis(2000)), - effects: vec![buff::BuffEffect::RepeatedHealthChange { - rate: 50.0, - accumulated: 0.0 + effects: vec![buff::BuffEffect::HealthChangeOverTime { + rate: 10.0, + accumulated: 0.0, }], }), }); diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 33170a9801..194daac982 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -6,8 +6,8 @@ use crate::{ use common::{ assets::Asset, comp::{ - self, - buff, chat::{KillSource, KillType}, + self, buff, + chat::{KillSource, KillType}, object, Alignment, Body, Damage, DamageSource, Group, HealthChange, HealthSource, Item, Player, Pos, Stats, }, @@ -675,7 +675,7 @@ pub fn handle_level_up(server: &mut Server, entity: EcsEntity, new_level: u32) { )); } -pub fn handle_buff(server: &mut Server, uid: Uid, buff: buff::BuffChange ) { +pub fn handle_buff(server: &mut Server, uid: Uid, buff: buff::BuffChange) { let ecs = &server.state.ecs(); let mut buffs_all = ecs.write_storage::(); if let Some(entity) = ecs.entity_from_uid(uid.into()) { @@ -706,7 +706,8 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff: buff::BuffChange ) { let buff = buffs.buffs.remove(i); for effect in &buff.effects { match effect { - // Only remove an effect here if its effect was not continuously applied + // Only remove an effect here if its effect was not continuously + // applied buff::BuffEffect::NameChange { prefix } => { if let Some(stats) = stats.get_mut(entity) { stats.name = stats.name.replace(prefix, ""); diff --git a/server/src/events/mod.rs b/server/src/events/mod.rs index 15ae546a04..359ebe0504 100644 --- a/server/src/events/mod.rs +++ b/server/src/events/mod.rs @@ -8,8 +8,8 @@ use entity_creation::{ handle_loaded_character_data, handle_shockwave, handle_shoot, }; use entity_manipulation::{ - handle_buff, handle_damage, handle_destroy, handle_explosion, handle_knockback, handle_land_on_ground, - handle_level_up, handle_respawn, + handle_buff, handle_damage, handle_destroy, handle_explosion, handle_knockback, + handle_land_on_ground, handle_level_up, handle_respawn, }; use group_manip::handle_group; use interaction::{handle_lantern, handle_mount, handle_possess, handle_unmount}; @@ -133,10 +133,7 @@ impl Server { ServerEvent::Chat(msg) => { chat_messages.push(msg); }, - ServerEvent::Buff { - uid, - buff, - } => handle_buff(self, uid, buff), + ServerEvent::Buff { uid, buff } => handle_buff(self, uid, buff), } } diff --git a/server/src/state_ext.rs b/server/src/state_ext.rs index a4208f0934..06d7c523e3 100644 --- a/server/src/state_ext.rs +++ b/server/src/state_ext.rs @@ -111,6 +111,7 @@ impl StateExt for State { .with(comp::Gravity(1.0)) .with(comp::CharacterState::default()) .with(loadout) + .with(comp::Buffs::default()) } fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder { @@ -202,6 +203,7 @@ impl StateExt for State { entity, comp::Alignment::Owned(self.read_component_copied(entity).unwrap()), ); + self.write_component(entity, comp::Buffs::default()); // Make sure physics components are updated self.write_component(entity, comp::ForceUpdate);