When buffs expire from duration, now only they expire rather than ending all buffs of the same type.

This commit is contained in:
Sam 2020-09-30 21:32:38 -05:00
parent 125de0b46e
commit b8690473e4
6 changed files with 59 additions and 52 deletions

View File

@ -81,7 +81,9 @@ pub enum BuffChange {
/// Adds this buff.
Add(Buff),
/// Removes all buffs with this ID.
Remove(BuffId),
RemoveById(BuffId),
/// Removes buff of this index
RemoveByIndex(Vec<usize>),
}
/// Source of the de/buff
@ -124,22 +126,6 @@ pub struct Buffs {
}
impl Buffs {
/// Adds a request for adding given `buff`.
/*pub fn add_buff(&mut self, buff: Buff) {
let change = BuffChange::Add(buff);
self.changes.push(change);
self.last_change = 0.0;
}
/// Adds a request for removal of all buffs with given Id.
/// TODO: Better removal, allowing to specify which ability to remove
/// directly.
pub fn remove_buff_by_id(&mut self, id: BuffId) {
let change = BuffChange::Remove(id);
self.changes.push(change);
self.last_change = 0.0;
}*/
/// This is a primitive check if a specific buff is present.
/// (for purposes like blocking usage of abilities or something like this).
pub fn has_buff_id(&self, id: &BuffId) -> bool { self.buffs.iter().any(|buff| buff.id == *id) }

View File

@ -108,7 +108,7 @@ pub enum ServerEvent {
Chat(comp::UnresolvedChatMsg),
Buff {
uid: Uid,
buff: comp::BuffChange,
buff_change: comp::BuffChange,
},
}

View File

@ -1,8 +1,10 @@
use crate::{
comp::{BuffChange, BuffEffect, BuffId, Buffs, HealthChange, HealthSource, Stats},
event::{EventBus, ServerEvent},
state::DeltaTime,
sync::Uid,
};
use specs::{Entities, Join, Read, System, WriteStorage};
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
use std::time::Duration;
/// This system modifies entity stats, changing them using buffs
@ -16,12 +18,15 @@ impl<'a> System<'a> for Sys {
type SystemData = (
Entities<'a>,
Read<'a, DeltaTime>,
Read<'a, EventBus<ServerEvent>>,
ReadStorage<'a, Uid>,
WriteStorage<'a, Stats>,
WriteStorage<'a, Buffs>,
);
fn run(&mut self, (entities, dt, mut stats, mut buffs): Self::SystemData) {
for (entity, mut buffs) in (&entities, &mut buffs.restrict_mut()).join() {
fn run(&mut self, (entities, dt, server_bus, uids, mut stats, mut buffs): Self::SystemData) {
let mut server_emitter = server_bus.emitter();
for (entity, uid, mut buffs) in (&entities, &uids, &mut buffs.restrict_mut()).join() {
let buff_comp = buffs.get_mut_unchecked();
let mut buff_indices_for_removal = Vec::new();
// Tick all de/buffs on a Buffs component.
@ -72,16 +77,21 @@ impl<'a> System<'a> for Sys {
};
}
}
server_emitter.emit(ServerEvent::Buff {
uid: *uid,
buff_change: BuffChange::RemoveByIndex(buff_indices_for_removal),
});
// 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
// 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() {
/*while !buff_indices_for_removal.is_empty() {
if let Some(i) = buff_indices_for_removal.pop() {
buff_comp.buffs.remove(i);
}
}
}*/
}
}
}

View File

@ -154,14 +154,19 @@ impl<'a> System<'a> for Sys {
// Test for server event of buff, remove before merging
server_emitter.emit(ServerEvent::Buff {
uid: *uid_b,
buff: buff::BuffChange::Add(buff::Buff {
buff_change: buff::BuffChange::Add(buff::Buff {
id: buff::BuffId::Bleeding,
cat_ids: vec![buff::BuffCategoryId::Physical],
time: Some(Duration::from_millis(2000)),
effects: vec![buff::BuffEffect::HealthChangeOverTime {
rate: 10.0,
accumulated: 0.0,
}],
effects: vec![
buff::BuffEffect::HealthChangeOverTime {
rate: 10.0,
accumulated: 0.0,
},
buff::BuffEffect::NameChange {
prefix: String::from("Injured "),
},
],
}),
});
attack.hit_count += 1;

View File

@ -675,13 +675,14 @@ 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_change: buff::BuffChange) {
let ecs = &server.state.ecs();
let mut buffs_all = ecs.write_storage::<comp::Buffs>();
if let Some(entity) = ecs.entity_from_uid(uid.into()) {
if let Some(buffs) = buffs_all.get_mut(entity) {
let mut stats = ecs.write_storage::<comp::Stats>();
match buff {
let mut buff_indices_for_removal = Vec::new();
match buff_change {
buff::BuffChange::Add(new_buff) => {
for effect in &new_buff.effects {
match effect {
@ -698,30 +699,35 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff: buff::BuffChange) {
}
buffs.buffs.push(new_buff.clone());
},
buff::BuffChange::Remove(id) => {
buff::BuffChange::RemoveByIndex(indices) => {
buff_indices_for_removal = indices;
},
buff::BuffChange::RemoveById(id) => {
let some_predicate = |current_id: &buff::BuffId| *current_id == id;
let mut i = 0;
while i != buffs.buffs.len() {
for i in 0..buffs.buffs.len() {
if some_predicate(&mut buffs.buffs[i].id) {
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
buff::BuffEffect::NameChange { prefix } => {
if let Some(stats) = stats.get_mut(entity) {
stats.name = stats.name.replace(prefix, "");
}
},
_ => {},
}
}
} else {
i += 1;
buff_indices_for_removal.push(i);
}
}
},
}
while !buff_indices_for_removal.is_empty() {
if let Some(i) = buff_indices_for_removal.pop() {
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
buff::BuffEffect::NameChange { prefix } => {
if let Some(stats) = stats.get_mut(entity) {
stats.name = stats.name.replacen(prefix, "", 1);
}
},
_ => {},
}
}
}
}
}
}
}

View File

@ -133,7 +133,7 @@ impl Server {
ServerEvent::Chat(msg) => {
chat_messages.push(msg);
},
ServerEvent::Buff { uid, buff } => handle_buff(self, uid, buff),
ServerEvent::Buff { uid, buff_change } => handle_buff(self, uid, buff_change),
}
}