Added functionality for buffs queueing. Saturation now queues.

This commit is contained in:
Sam 2021-02-20 15:37:46 -05:00
parent f5a74b4f33
commit f24490dc80
3 changed files with 53 additions and 25 deletions

View File

@ -31,7 +31,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Basic NPC interaction - Basic NPC interaction
- Lights in dungeons - Lights in dungeons
- Trading system (bound to the `R` key by default, currently only works with players) - Trading system (bound to the `R` key by default, currently only works with players)
- Support for dual wielding (not accessible as animations still needed)
- Support for modular weapons. - Support for modular weapons.
- Saturation buff (healing from food) now queues
### Changed ### Changed

View File

@ -29,19 +29,22 @@ pub enum BuffKind {
} }
impl BuffKind { impl BuffKind {
// Checks if buff is buff or debuff /// Checks if buff is buff or debuff
pub fn is_buff(self) -> bool { pub fn is_buff(self) -> bool {
match self { match self {
BuffKind::Regeneration { .. } => true, BuffKind::Regeneration => true,
BuffKind::Saturation { .. } => true, BuffKind::Saturation => true,
BuffKind::Bleeding { .. } => false, BuffKind::Bleeding => false,
BuffKind::Cursed { .. } => false, BuffKind::Cursed => false,
BuffKind::Potion { .. } => true, BuffKind::Potion => true,
BuffKind::CampfireHeal { .. } => true, BuffKind::CampfireHeal => true,
BuffKind::IncreaseMaxEnergy { .. } => true, BuffKind::IncreaseMaxEnergy => true,
BuffKind::IncreaseMaxHealth { .. } => true, BuffKind::IncreaseMaxHealth => true,
} }
} }
/// Checks if buff should queue
pub fn queues(self) -> bool { matches!(self, BuffKind::Saturation) }
} }
// Struct used to store data relevant to a buff // Struct used to store data relevant to a buff
@ -321,7 +324,6 @@ impl Buffs {
// Gets most powerful buff of a given kind // Gets most powerful buff of a given kind
// pub fn get_active_kind(&self, kind: BuffKind) -> Buff // pub fn get_active_kind(&self, kind: BuffKind) -> Buff
pub fn remove(&mut self, buff_id: BuffId) { pub fn remove(&mut self, buff_id: BuffId) {
let kind = self.buffs.remove(&buff_id).unwrap().kind; let kind = self.buffs.remove(&buff_id).unwrap().kind;
self.kinds self.kinds
@ -329,6 +331,12 @@ impl Buffs {
.map(|ids| ids.retain(|id| *id != buff_id)); .map(|ids| ids.retain(|id| *id != buff_id));
self.sort_kind(kind); self.sort_kind(kind);
} }
/// Returns an immutable reference to the buff kinds on an entity, and a
/// mutable reference to the buffs
pub fn parts(&mut self) -> (&HashMap<BuffKind, Vec<BuffId>>, &mut HashMap<BuffId, Buff>) {
(&self.kinds, &mut self.buffs)
}
} }
pub type BuffId = u64; pub type BuffId = u64;

View File

@ -1,6 +1,6 @@
use common::{ use common::{
comp::{ comp::{
BuffCategory, BuffChange, BuffEffect, BuffId, BuffSource, Buffs, Energy, Health, Buff, BuffCategory, BuffChange, BuffEffect, BuffId, BuffSource, Buffs, Energy, Health,
HealthChange, HealthSource, Inventory, ModifierKind, HealthChange, HealthSource, Inventory, ModifierKind,
}, },
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
@ -35,22 +35,24 @@ impl<'a> System<'a> for Sys {
for (entity, mut buff_comp, mut health, mut energy) in for (entity, mut buff_comp, mut health, mut energy) in
(&entities, &mut buffs, &mut healths, &mut energies).join() (&entities, &mut buffs, &mut healths, &mut energies).join()
{ {
let (buff_comp_kinds, buff_comp_buffs) = buff_comp.parts();
let mut expired_buffs = Vec::<BuffId>::new(); let mut expired_buffs = Vec::<BuffId>::new();
for (id, buff) in buff_comp.buffs.iter_mut() { // For each buff kind present on entity, if the buff kind queues, only ticks
// Tick the buff and subtract delta from it // duration of strongest buff of that kind, else it ticks durations of all buffs
if let Some(remaining_time) = &mut buff.time { // of that kind. Any buffs whose durations expire are marked expired.
if let Some(new_duration) = for (kind, ids) in buff_comp_kinds.iter() {
remaining_time.checked_sub(Duration::from_secs_f32(dt.0)) if kind.queues() {
if let Some((Some(buff), id)) =
ids.get(0).map(|id| (buff_comp_buffs.get_mut(id), id))
{ {
// The buff still continues. tick_buff(*id, buff, dt.0, |id| expired_buffs.push(id));
*remaining_time = new_duration; }
} else { } else {
// checked_sub returns None when remaining time for (id, buff) in buff_comp_buffs
// went below 0, so set to 0 .iter_mut()
*remaining_time = Duration::default(); .filter(|(i, _)| ids.iter().any(|id| id == *i))
// The buff has expired. {
// Remove it. tick_buff(*id, buff, dt.0, |id| expired_buffs.push(id));
expired_buffs.push(*id);
} }
} }
} }
@ -172,3 +174,19 @@ impl<'a> System<'a> for Sys {
energies.set_event_emission(true); energies.set_event_emission(true);
} }
} }
fn tick_buff(id: u64, buff: &mut Buff, dt: f32, mut expire_buff: impl FnMut(u64)) {
if let Some(remaining_time) = &mut buff.time {
if let Some(new_duration) = remaining_time.checked_sub(Duration::from_secs_f32(dt)) {
// The buff still continues.
*remaining_time = new_duration;
} else {
// checked_sub returns None when remaining time
// went below 0, so set to 0
*remaining_time = Duration::default();
// The buff has expired.
// Remove it.
expire_buff(id);
}
}
}