Fixed issue with max health change over time buff being reset if re-applied. Addressed review comments.

This commit is contained in:
Sam 2023-03-12 16:37:02 -04:00
parent 4c79936c07
commit 42388976d7
4 changed files with 28 additions and 23 deletions

View File

@ -424,7 +424,9 @@ fn compare_end_time(a: Option<Time>, b: Option<Time>) -> bool {
#[cfg(not(target_arch = "wasm32"))]
impl PartialEq for Buff {
fn eq(&self, other: &Self) -> bool {
self.data.strength == other.data.strength && self.end_time == other.end_time
self.data.strength == other.data.strength
&& self.end_time == other.end_time
&& self.start_time == other.start_time
}
}
@ -461,8 +463,10 @@ pub enum BuffSource {
pub struct Buffs {
/// Uid used for synchronization
id_counter: u64,
/// Maps Kinds of buff to Id's of currently applied buffs of that kind
pub kinds: HashMap<BuffKind, Vec<BuffId>>,
/// Maps Kinds of buff to Id's of currently applied buffs of that kind and
/// the time that the first buff was added (time gets reset if entity no
/// longer has buffs of that kind)
pub kinds: HashMap<BuffKind, (Vec<BuffId>, Time)>,
// All currently applied buffs stored by Id
pub buffs: HashMap<BuffId, Buff>,
}
@ -471,13 +475,14 @@ pub struct Buffs {
impl Buffs {
fn sort_kind(&mut self, kind: BuffKind) {
if let Some(buff_order) = self.kinds.get_mut(&kind) {
if buff_order.is_empty() {
if buff_order.0.is_empty() {
self.kinds.remove(&kind);
} else {
let buffs = &self.buffs;
// Intentionally sorted in reverse so that the strongest buffs are earlier in
// the vector
buff_order
.0
.sort_by(|a, b| buffs[b].partial_cmp(&buffs[a]).unwrap_or(Ordering::Equal));
}
}
@ -485,7 +490,7 @@ impl Buffs {
pub fn remove_kind(&mut self, kind: BuffKind) {
if let Some(buff_ids) = self.kinds.get_mut(&kind) {
for id in buff_ids {
for id in &buff_ids.0 {
self.buffs.remove(id);
}
self.kinds.remove(&kind);
@ -494,7 +499,11 @@ impl Buffs {
fn force_insert(&mut self, id: BuffId, buff: Buff, current_time: Time) -> BuffId {
let kind = buff.kind;
self.kinds.entry(kind).or_default().push(id);
self.kinds
.entry(kind)
.or_insert((Vec::new(), current_time))
.0
.push(id);
self.buffs.insert(id, buff);
self.sort_kind(kind);
if kind.queues() {
@ -514,7 +523,7 @@ impl Buffs {
pub fn iter_kind(&self, kind: BuffKind) -> impl Iterator<Item = (BuffId, &Buff)> + '_ {
self.kinds
.get(&kind)
.map(|ids| ids.iter())
.map(|ids| ids.0.iter())
.unwrap_or_else(|| [].iter())
.map(move |id| (*id, &self.buffs[id]))
}
@ -526,9 +535,9 @@ impl Buffs {
if kind.stacks() {
// Iterate stackable buffs in reverse order to show the timer of the soonest one
// to expire
Either::Left(ids.iter().filter_map(|id| self.buffs.get(id)).rev())
Either::Left(ids.0.iter().filter_map(|id| self.buffs.get(id)).rev())
} else {
Either::Right(self.buffs.get(&ids[0]).into_iter())
Either::Right(self.buffs.get(&ids.0[0]).into_iter())
}
})
}
@ -539,22 +548,16 @@ impl Buffs {
let kind = kind.kind;
self.kinds
.get_mut(&kind)
.map(|ids| ids.retain(|id| *id != buff_id));
.map(|ids| ids.0.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)
}
fn delay_queueable_buffs(&mut self, kind: BuffKind, current_time: Time) {
let mut next_start_time: Option<Time> = None;
debug_assert!(kind.queues());
if let Some(buffs) = self.kinds.get(&kind) {
buffs.iter().for_each(|id| {
buffs.0.iter().for_each(|id| {
if let Some(buff) = self.buffs.get_mut(id) {
// End time only being updated when there is some next_start_time will
// technically cause buffs to "end early" if they have a weaker strength than a

View File

@ -329,9 +329,9 @@ impl<'a> System<'a> for Sys {
.kinds
.iter()
.map(|(kind, ids)| (*kind, ids.clone()))
.collect::<Vec<(BuffKind, Vec<BuffId>)>>();
.collect::<Vec<(BuffKind, (Vec<BuffId>, Time))>>();
buff_kinds.sort_by_key(|(kind, _)| !kind.affects_subsequent_buffs());
for (buff_kind, buff_ids) in buff_kinds.into_iter() {
for (buff_kind, (buff_ids, kind_start_time)) in buff_kinds.into_iter() {
let mut active_buff_ids = Vec::new();
if buff_kind.stacks() {
// Process all the buffs of this kind
@ -359,6 +359,7 @@ impl<'a> System<'a> for Sys {
effect,
buff.kind,
buff.start_time,
kind_start_time,
&read_data,
&mut stat,
health,
@ -404,6 +405,7 @@ fn execute_effect(
effect: &BuffEffect,
buff_kind: BuffKind,
buff_start_time: Time,
buff_kind_start_time: Time,
read_data: &ReadData,
stat: &mut Stats,
health: &Health,
@ -515,7 +517,7 @@ fn execute_effect(
kind,
target_fraction,
} => {
let potential_amount = (time.0 - buff_start_time.0) as f32 * rate;
let potential_amount = (time.0 - buff_kind_start_time.0) as f32 * rate;
// Percentage change that should be applied to max_health
let potential_fraction = 1.0

View File

@ -1308,10 +1308,10 @@ pub fn handle_parry_hook(server: &Server, defender: EcsEntity, attacker: Option<
let duration = char_state
.durations()
.and_then(|durs| durs.recover)
.map_or(0.5, |dur| dur.as_secs_f32())
.map_or(0.5, |dur| dur.as_secs_f64())
.max(0.5)
.mul(2.0);
let data = buff::BuffData::new(1.0, Some(Secs(duration as f64)), None);
let data = buff::BuffData::new(1.0, Some(Secs(duration)), None);
let source = if let Some(uid) = ecs.read_storage::<Uid>().get(defender) {
BuffSource::Character { by: *uid }
} else {

View File

@ -1312,7 +1312,7 @@ impl ParticleMgr {
let mut multiplicity = 0;
// Only show particles for potion sickness at the beginning, after the
// drinking animation finishes
if buff_ids
if buff_ids.0
.iter()
.filter_map(|id| buffs.buffs.get(id))
.any(|buff| {