Added wrapper type to durations related to buffs and auras.

This commit is contained in:
Sam 2023-03-11 16:44:57 -05:00
parent 663db06844
commit 4c79936c07
19 changed files with 71 additions and 51 deletions

View File

@ -13,6 +13,7 @@ use crate::{
},
event::ServerEvent,
outcome::Outcome,
resources::Secs,
states::utils::StageSection,
uid::{Uid, UidAllocator},
util::Dir,
@ -1049,7 +1050,7 @@ impl CombatBuff {
self.kind,
BuffData::new(
self.strength.to_strength(damage, strength_modifier),
Some(self.dur_secs as f64),
Some(Secs(self.dur_secs as f64)),
None,
),
Vec::new(),

View File

@ -20,6 +20,7 @@ use crate::{
},
Body, CharacterState, LightEmitter, StateUpdate,
},
resources::Secs,
states::{
behavior::JoinData,
utils::{AbilityInfo, StageSection},
@ -696,7 +697,7 @@ pub enum CharacterAbility {
recover_duration: f32,
targets: combat::GroupTarget,
auras: Vec<aura::AuraBuffConstructor>,
aura_duration: f64,
aura_duration: Secs,
range: f32,
energy_cost: f32,
scales_with_combo: bool,
@ -728,7 +729,7 @@ pub enum CharacterAbility {
recover_duration: f32,
buff_kind: buff::BuffKind,
buff_strength: f32,
buff_duration: Option<f64>,
buff_duration: Option<Secs>,
energy_cost: f32,
#[serde(default)]
meta: AbilityMeta,

View File

@ -1,7 +1,7 @@
use crate::{
combat::GroupTarget,
comp::buff::{BuffCategory, BuffData, BuffKind, BuffSource},
resources::Time,
resources::{Secs, Time},
uid::Uid,
};
use serde::{Deserialize, Serialize};
@ -92,12 +92,12 @@ impl From<(Option<GroupTarget>, Option<&Uid>)> for AuraTarget {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuraData {
pub duration: Option<f64>,
pub duration: Option<Secs>,
}
impl AuraData {
#[must_use]
fn new(duration: Option<f64>) -> Self { Self { duration } }
fn new(duration: Option<Secs>) -> Self { Self { duration } }
}
impl Aura {
@ -105,14 +105,14 @@ impl Aura {
pub fn new(
aura_kind: AuraKind,
radius: f32,
duration: Option<f64>,
duration: Option<Secs>,
target: AuraTarget,
time: Time,
) -> Self {
Self {
aura_kind,
radius,
end_time: duration.map(|dur| Time(time.0 + dur)),
end_time: duration.map(|dur| Time(time.0 + dur.0)),
target,
data: AuraData::new(duration),
}
@ -143,7 +143,7 @@ impl Auras {
pub struct AuraBuffConstructor {
pub kind: BuffKind,
pub strength: f32,
pub duration: Option<f64>,
pub duration: Option<Secs>,
pub category: BuffCategory,
}
@ -152,7 +152,7 @@ impl AuraBuffConstructor {
self,
uid: &Uid,
radius: f32,
duration: Option<f64>,
duration: Option<Secs>,
target: AuraTarget,
time: Time,
) -> Aura {

View File

@ -1,7 +1,7 @@
#![allow(clippy::nonstandard_macro_braces)] //tmp as of false positive !?
use crate::{
comp::{aura::AuraKey, Stats},
resources::Time,
resources::{Secs, Time},
uid::Uid,
};
use core::cmp::Ordering;
@ -147,13 +147,13 @@ impl BuffKind {
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct BuffData {
pub strength: f32,
pub duration: Option<f64>,
pub delay: Option<f64>,
pub duration: Option<Secs>,
pub delay: Option<Secs>,
}
#[cfg(not(target_arch = "wasm32"))]
impl BuffData {
pub fn new(strength: f32, duration: Option<f64>, delay: Option<f64>) -> Self {
pub fn new(strength: f32, duration: Option<Secs>, delay: Option<Secs>) -> Self {
Self {
strength,
duration,
@ -369,14 +369,14 @@ impl Buff {
BuffKind::Parried => vec![BuffEffect::AttackSpeed(0.5)],
BuffKind::PotionSickness => vec![BuffEffect::HealReduction(data.strength)],
};
let start_time = Time(time.0 + data.delay.unwrap_or(0.0));
let start_time = Time(time.0 + data.delay.map_or(0.0, |delay| delay.0));
let end_time = if cat_ids
.iter()
.any(|cat_id| matches!(cat_id, BuffCategory::FromActiveAura(..)))
{
None
} else {
data.duration.map(|dur| Time(start_time.0 + dur))
data.duration.map(|dur| Time(start_time.0 + dur.0))
};
Buff {
kind,
@ -390,7 +390,7 @@ impl Buff {
}
/// Calculate how much time has elapsed since the buff was applied
pub fn elapsed(&self, time: Time) -> f64 { time.0 - self.start_time.0 }
pub fn elapsed(&self, time: Time) -> Secs { Secs(time.0 - self.start_time.0) }
}
#[cfg(not(target_arch = "wasm32"))]
@ -603,6 +603,7 @@ pub mod tests {
Vec::new(),
BuffSource::Unknown,
time,
None,
)
}
@ -611,7 +612,7 @@ pub mod tests {
/// queue has correct total duration
fn test_queueable_buffs_three() {
let mut buff_comp: Buffs = Default::default();
let buff_data = BuffData::new(1.0, Some(10.0), None);
let buff_data = BuffData::new(1.0, Some(Secs(10.0)), None);
let time_a = Time(0.0);
buff_comp.insert(create_test_queueable_buff(buff_data, time_a), time_a);
let time_b = Time(6.0);
@ -642,8 +643,8 @@ pub mod tests {
/// queueable buff is added, delayed buff has correct start time
fn test_queueable_buff_delay_start() {
let mut buff_comp: Buffs = Default::default();
let queued_buff_data = BuffData::new(1.0, Some(10.0), Some(10.0));
let buff_data = BuffData::new(1.0, Some(10.0), None);
let queued_buff_data = BuffData::new(1.0, Some(Secs(10.0)), Some(Secs(10.0)));
let buff_data = BuffData::new(1.0, Some(Secs(10.0)), None);
let time_a = Time(0.0);
buff_comp.insert(create_test_queueable_buff(queued_buff_data, time_a), time_a);
let time_b = Time(6.0);
@ -674,8 +675,8 @@ pub mod tests {
/// does not move delayed buff start or end times
fn test_queueable_buff_long_delay() {
let mut buff_comp: Buffs = Default::default();
let queued_buff_data = BuffData::new(1.0, Some(10.0), Some(50.0));
let buff_data = BuffData::new(1.0, Some(10.0), None);
let queued_buff_data = BuffData::new(1.0, Some(Secs(10.0)), Some(Secs(50.0)));
let buff_data = BuffData::new(1.0, Some(Secs(10.0)), None);
let time_a = Time(0.0);
buff_comp.insert(create_test_queueable_buff(queued_buff_data, time_a), time_a);
let time_b = Time(10.0);

View File

@ -3,6 +3,7 @@ use crate::comp::Pos;
use serde::{Deserialize, Serialize};
#[cfg(not(target_arch = "wasm32"))]
use specs::Entity;
use std::ops::{Mul, MulAssign};
/// A resource that stores the time of day.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Default)]
@ -16,6 +17,20 @@ pub struct Time(pub f64);
#[derive(Default)]
pub struct DeltaTime(pub f32);
/// A resource used to indicate a duration of time, in seconds
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[serde(transparent)]
pub struct Secs(pub f64);
impl Mul<f64> for Secs {
type Output = Self;
fn mul(self, mult: f64) -> Self { Self(self.0 * mult) }
}
impl MulAssign<f64> for Secs {
fn mul_assign(&mut self, mult: f64) { *self = *self * mult; }
}
#[cfg(not(target_arch = "wasm32"))]
#[derive(Default)]
pub struct EntitiesDiedLastTick(pub Vec<(Entity, Pos)>);

View File

@ -6,6 +6,7 @@ use crate::{
CharacterState, StateUpdate,
},
event::ServerEvent,
resources::Secs,
states::{
behavior::{CharacterBehavior, JoinData},
utils::*,
@ -28,7 +29,7 @@ pub struct StaticData {
/// Has information used to construct the auras
pub auras: Vec<AuraBuffConstructor>,
/// How long aura lasts
pub aura_duration: f64,
pub aura_duration: Secs,
/// Radius of aura
pub range: f32,
/// What key is used to press ability

View File

@ -5,6 +5,7 @@ use crate::{
CharacterState, StateUpdate,
},
event::ServerEvent,
resources::Secs,
states::{
behavior::{CharacterBehavior, JoinData},
utils::*,
@ -27,7 +28,7 @@ pub struct StaticData {
/// Strength of the created buff
pub buff_strength: f32,
/// How long buff lasts
pub buff_duration: Option<f64>,
pub buff_duration: Option<Secs>,
/// What key is used to press ability
pub ability_info: AbilityInfo,
}

View File

@ -13,7 +13,7 @@ use common::{
Pos, Stats,
},
event::{Emitter, EventBus, ServerEvent},
resources::{DeltaTime, Time},
resources::{DeltaTime, Secs, Time},
terrain::SpriteKind,
uid::{Uid, UidAllocator},
Damage, DamageSource,
@ -146,7 +146,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Ensnared,
BuffData::new(1.0, Some(1.0), None),
BuffData::new(1.0, Some(Secs(1.0)), None),
Vec::new(),
BuffSource::World,
*read_data.time,
@ -163,7 +163,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Bleeding,
BuffData::new(1.0, Some(6.0), None),
BuffData::new(1.0, Some(Secs(6.0)), None),
Vec::new(),
BuffSource::World,
*read_data.time,
@ -180,7 +180,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Bleeding,
BuffData::new(15.0, Some(0.1), None),
BuffData::new(15.0, Some(Secs(0.1)), None),
Vec::new(),
BuffSource::World,
*read_data.time,
@ -192,7 +192,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Frozen,
BuffData::new(0.2, Some(1.0), None),
BuffData::new(0.2, Some(Secs(1.0)), None),
Vec::new(),
BuffSource::World,
*read_data.time,

View File

@ -558,7 +558,7 @@ impl<'a> AgentData<'a> {
Effect::Buff(BuffEffect { kind, data, .. })
if matches!(kind, Regeneration | Saturation | Potion) =>
{
value += data.strength * data.duration.map_or(0.0, |d| d as f32);
value += data.strength * data.duration.map_or(0.0, |d| d.0 as f32);
},
Effect::Buff(BuffEffect { kind, .. })
if matches!(kind, PotionSickness) =>

View File

@ -42,7 +42,7 @@ use common::{
npc::{self, get_npc_name},
outcome::Outcome,
parse_cmd_args,
resources::{BattleMode, PlayerPhysicsSettings, Time, TimeOfDay},
resources::{BattleMode, PlayerPhysicsSettings, Secs, Time, TimeOfDay},
terrain::{Block, BlockKind, CoordinateConversions, SpriteKind, TerrainChunkSize},
uid::{Uid, UidAllocator},
vol::ReadVol,
@ -1479,7 +1479,7 @@ fn handle_spawn_campfire(
Aura::new(
AuraKind::Buff {
kind: BuffKind::CampfireHeal,
data: BuffData::new(0.02, Some(1.0), None),
data: BuffData::new(0.02, Some(Secs(1.0)), None),
category: BuffCategory::Natural,
source: BuffSource::World,
},
@ -1491,7 +1491,7 @@ fn handle_spawn_campfire(
Aura::new(
AuraKind::Buff {
kind: BuffKind::Burning,
data: BuffData::new(2.0, Some(10.0), None),
data: BuffData::new(2.0, Some(Secs(10.0)), None),
category: BuffCategory::Natural,
source: BuffSource::World,
},
@ -3522,7 +3522,7 @@ fn handle_buff(
if let (Some(buff), strength, duration) = parse_cmd_args!(args, String, f32, f64) {
let strength = strength.unwrap_or(0.01);
let duration = duration.unwrap_or(1.0);
let buffdata = BuffData::new(strength, Some(duration), None);
let buffdata = BuffData::new(strength, Some(Secs(duration)), None);
if buff != "all" {
cast_buff(&buff, buffdata, server, target)
} else {

View File

@ -14,7 +14,7 @@ use common::{
event::{EventBus, UpdateCharacterMetadata},
lottery::LootSpec,
outcome::Outcome,
resources::Time,
resources::{Secs, Time},
rtsim::RtSimEntity,
uid::Uid,
util::Dir,
@ -286,7 +286,7 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3<f32>) {
Aura::new(
AuraKind::Buff {
kind: BuffKind::CampfireHeal,
data: BuffData::new(0.02, Some(1.0), None),
data: BuffData::new(0.02, Some(Secs(1.0)), None),
category: BuffCategory::Natural,
source: BuffSource::World,
},
@ -298,7 +298,7 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3<f32>) {
Aura::new(
AuraKind::Buff {
kind: BuffKind::Burning,
data: BuffData::new(2.0, Some(10.0), None),
data: BuffData::new(2.0, Some(Secs(10.0)), None),
category: BuffCategory::Natural,
source: BuffSource::World,
},

View File

@ -25,7 +25,7 @@ use common::{
},
event::{EventBus, ServerEvent},
outcome::{HealthChangeInfo, Outcome},
resources::Time,
resources::{Secs, Time},
rtsim::RtSimEntity,
states::utils::{AbilityInfo, StageSection},
terrain::{Block, BlockKind, TerrainGrid},
@ -1311,7 +1311,7 @@ pub fn handle_parry_hook(server: &Server, defender: EcsEntity, attacker: Option<
.map_or(0.5, |dur| dur.as_secs_f32())
.max(0.5)
.mul(2.0);
let data = buff::BuffData::new(1.0, Some(duration as f64), None);
let data = buff::BuffData::new(1.0, Some(Secs(duration as f64)), None);
let source = if let Some(uid) = ecs.read_storage::<Uid>().get(defender) {
BuffSource::Character { by: *uid }
} else {

View File

@ -23,7 +23,7 @@ use common::{
effect::Effect,
link::{Link, LinkHandle},
mounting::Mounting,
resources::{Time, TimeOfDay},
resources::{Secs, Time, TimeOfDay},
slowjob::SlowJobPool,
uid::{Uid, UidAllocator},
LoadoutBuilder, ViewDistances,
@ -439,7 +439,7 @@ impl StateExt for State {
.with(Auras::new(vec![Aura::new(
AuraKind::Buff {
kind: BuffKind::Invulnerability,
data: BuffData::new(1.0, Some(1.0), None),
data: BuffData::new(1.0, Some(Secs(1.0)), None),
category: BuffCategory::Natural,
source: BuffSource::World,
},

View File

@ -227,7 +227,7 @@ impl<'a> Widget for BuffsBar<'a> {
let max_duration = buff.kind.max_duration();
let current_duration = buff.end_time.map(|end| end - self.time.0);
let duration_percentage = current_duration.map_or(1000.0, |cur| {
max_duration.map_or(1000.0, |max| cur / max * 1000.0)
max_duration.map_or(1000.0, |max| cur / max.0 * 1000.0)
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
let buff_img = buff.kind.image(self.imgs);
let buff_widget = Image::new(buff_img).w_h(40.0, 40.0);
@ -309,7 +309,7 @@ impl<'a> Widget for BuffsBar<'a> {
let max_duration = debuff.kind.max_duration();
let current_duration = debuff.end_time.map(|end| end - self.time.0);
let duration_percentage = current_duration.map_or(1000.0, |cur| {
max_duration.map_or(1000.0, |max| cur / max * 1000.0)
max_duration.map_or(1000.0, |max| cur / max.0 * 1000.0)
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
let debuff_img = debuff.kind.image(self.imgs);
let debuff_widget = Image::new(debuff_img).w_h(40.0, 40.0);
@ -408,7 +408,7 @@ impl<'a> Widget for BuffsBar<'a> {
let current_duration = buff.end_time.map(|end| end - self.time.0);
// Percentage to determine which frame of the timer overlay is displayed
let duration_percentage = current_duration.map_or(1000.0, |cur| {
max_duration.map_or(1000.0, |max| cur / max * 1000.0)
max_duration.map_or(1000.0, |max| cur / max.0 * 1000.0)
}) as u32;
let buff_img = buff.kind.image(self.imgs);
let buff_widget = Image::new(buff_img).w_h(40.0, 40.0);

View File

@ -538,7 +538,7 @@ impl<'a> Widget for Group<'a> {
let norm_col = Color::Rgba(1.0, 1.0, 1.0, 1.0);
let current_duration = buff.end_time.map(|end| end - self.time.0);
let duration_percentage = current_duration.map_or(1000.0, |cur| {
max_duration.map_or(1000.0, |max| cur / max * 1000.0)
max_duration.map_or(1000.0, |max| cur / max.0 * 1000.0)
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
let buff_img = buff.kind.image(self.imgs);
let buff_widget = Image::new(buff_img).w_h(15.0, 15.0);

View File

@ -104,7 +104,7 @@ use common::{
link::Is,
mounting::Mount,
outcome::Outcome,
resources::Time,
resources::{Secs, Time},
slowjob::SlowJobPool,
terrain::{SpriteKind, TerrainChunk, UnlockKind},
trade::{ReducedInventory, TradeAction},
@ -482,7 +482,7 @@ impl<'a> BuffIconKind<'a> {
}
}
pub fn max_duration(&self) -> Option<f64> {
pub fn max_duration(&self) -> Option<Secs> {
match self {
Self::Buff { data, .. } => data.duration,
Self::Ability { .. } => None,

View File

@ -272,7 +272,7 @@ impl<'a> Widget for Overhead<'a> {
let max_duration = buff.kind.max_duration();
let current_duration = buff.end_time.map(|end| end - self.time.0);
let duration_percentage = current_duration.map_or(1000.0, |cur| {
max_duration.map_or(1000.0, |max| cur / max * 1000.0)
max_duration.map_or(1000.0, |max| cur / max.0 * 1000.0)
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
let buff_img = buff.kind.image(self.imgs);
let buff_widget = Image::new(buff_img).w_h(20.0, 20.0);

View File

@ -146,7 +146,7 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> Vec<String> {
let mut description = String::new();
if let Effect::Buff(buff) = effect {
let strength = buff.data.strength;
let dur_secs = buff.data.duration.map(|d| d as f32);
let dur_secs = buff.data.duration.map(|d| d.0 as f32);
let str_total = dur_secs.map_or(strength, |secs| strength * secs);
let format_float =

View File

@ -1226,7 +1226,7 @@ impl ParticleMgr {
} => {
let is_new_aura = aura.data.duration.map_or(true, |max_dur| {
let rem_dur = aura.end_time.map_or(time, |e| e.0) - time;
rem_dur > max_dur * 0.9
rem_dur > max_dur.0 * 0.9
});
if is_new_aura {
let heartbeats = self.scheduler.heartbeats(Duration::from_millis(5));
@ -1316,7 +1316,7 @@ impl ParticleMgr {
.iter()
.filter_map(|id| buffs.buffs.get(id))
.any(|buff| {
matches!(buff.elapsed(Time(time)), dur if (1.0..=1.5).contains(&dur))
matches!(buff.elapsed(Time(time)), dur if (1.0..=1.5).contains(&dur.0))
})
{
multiplicity = 1;