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
- Lights in dungeons
- 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.
- Saturation buff (healing from food) now queues
### Changed

View File

@ -29,19 +29,22 @@ pub enum BuffKind {
}
impl BuffKind {
// Checks if buff is buff or debuff
/// Checks if buff is buff or debuff
pub fn is_buff(self) -> bool {
match self {
BuffKind::Regeneration { .. } => true,
BuffKind::Saturation { .. } => true,
BuffKind::Bleeding { .. } => false,
BuffKind::Cursed { .. } => false,
BuffKind::Potion { .. } => true,
BuffKind::CampfireHeal { .. } => true,
BuffKind::IncreaseMaxEnergy { .. } => true,
BuffKind::IncreaseMaxHealth { .. } => true,
BuffKind::Regeneration => true,
BuffKind::Saturation => true,
BuffKind::Bleeding => false,
BuffKind::Cursed => false,
BuffKind::Potion => true,
BuffKind::CampfireHeal => true,
BuffKind::IncreaseMaxEnergy => 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
@ -321,7 +324,6 @@ impl Buffs {
// Gets most powerful buff of a given kind
// pub fn get_active_kind(&self, kind: BuffKind) -> Buff
pub fn remove(&mut self, buff_id: BuffId) {
let kind = self.buffs.remove(&buff_id).unwrap().kind;
self.kinds
@ -329,6 +331,12 @@ impl Buffs {
.map(|ids| ids.retain(|id| *id != buff_id));
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;

View File

@ -1,6 +1,6 @@
use common::{
comp::{
BuffCategory, BuffChange, BuffEffect, BuffId, BuffSource, Buffs, Energy, Health,
Buff, BuffCategory, BuffChange, BuffEffect, BuffId, BuffSource, Buffs, Energy, Health,
HealthChange, HealthSource, Inventory, ModifierKind,
},
event::{EventBus, ServerEvent},
@ -35,22 +35,24 @@ impl<'a> System<'a> for Sys {
for (entity, mut buff_comp, mut health, mut energy) in
(&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();
for (id, buff) in buff_comp.buffs.iter_mut() {
// Tick the buff and subtract delta from it
if let Some(remaining_time) = &mut buff.time {
if let Some(new_duration) =
remaining_time.checked_sub(Duration::from_secs_f32(dt.0))
// For each buff kind present on entity, if the buff kind queues, only ticks
// duration of strongest buff of that kind, else it ticks durations of all buffs
// of that kind. Any buffs whose durations expire are marked expired.
for (kind, ids) in buff_comp_kinds.iter() {
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.
*remaining_time = new_duration;
tick_buff(*id, buff, dt.0, |id| expired_buffs.push(id));
}
} 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.
expired_buffs.push(*id);
for (id, buff) in buff_comp_buffs
.iter_mut()
.filter(|(i, _)| ids.iter().any(|id| id == *i))
{
tick_buff(*id, buff, dt.0, |id| expired_buffs.push(id));
}
}
}
@ -172,3 +174,19 @@ impl<'a> System<'a> for Sys {
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);
}
}
}