Skip to main content

wowlab_engine_domain/rotation/buffer/
aura.rs

1pub use wowlab_types::sim::{AuraKey, AuraOn, AuraProjectionKey};
2
3wowlab_engine_macros::define_slot! {
4    #[slot(domain = "aura", kind = keyed, key_domain = "aura")]
5    pub struct AuraSlot {
6        #[expr("is_active", Float, TimestampActive)]
7        #[expr("remaining", Float, TimestampRemaining)]
8        #[expr("elapsed", Float, TimestampElapsed)]
9        #[expr("is_inactive", Float, TimestampInactive)]
10        #[expr("is_refreshable", Float, AuraRefreshable)]
11        pub expires_at: f64,
12
13        #[expr("duration", Float, Direct)]
14        pub base_duration: f64,
15
16        #[expr("stacks", Int, Direct)]
17        #[expr("value", Int, Direct)]
18        #[expr("react", Int, Direct)]
19        pub stacks: i32,
20
21        #[expr("stacks_max", Int, Direct)]
22        pub max_stacks: i32,
23
24        #[expr("next_tick", Float, TimestampRemaining)]
25        pub next_tick: f64,
26
27        #[expr("tick_time", Float, Direct)]
28        #[expr("is_ticking", Float, PositiveFloat)]
29        pub tick_interval: f64,
30
31        /// Unhasted tick interval, set at apply; used to recompute next tick against current haste.
32        pub base_tick_interval: f64,
33
34        /// Current SimC-compatible wall-clock multiplier from aura time-rate effects.
35        pub time_rate_multiplier: f64,
36
37        #[expr("ticks_remaining", Int, Direct)]
38        pub remaining_ticks: i32,
39
40        /// `1` when the aura carries a source-side stat snapshot, `0` for live/dynamic stats.
41        pub snapshot_has: i32,
42
43        pub snapshot_ap: f64,
44        pub snapshot_sp: f64,
45        pub snapshot_crit: f64,
46        pub snapshot_vers: f64,
47        pub snapshot_mastery_mult: f64,
48        /// Rolling damage multiplier; pandemic "keep higher" compares this.
49        pub snapshot_damage_mult: f64,
50    }
51
52    impl {
53        #[inline]
54        pub fn remove(&mut self) {
55            *self = Self::default();
56        }
57
58        /// True when the slot holds an aura instance, regardless of active state at any `now`.
59        #[inline]
60        #[must_use]
61        pub fn is_occupied(&self) -> bool {
62            self.expires_at > 0.0
63        }
64
65        /// True when occupied and not yet expired at `now`; exact negation of `is_inactive`.
66        #[inline]
67        #[must_use]
68        pub fn is_active(&self, now: f64) -> bool {
69            self.expires_at > 0.0 && now < self.expires_at
70        }
71
72        #[inline]
73        #[must_use]
74        pub fn is_inactive(&self, now: f64) -> bool {
75            !self.is_active(now)
76        }
77
78        #[must_use]
79        pub fn is_refreshable(&self, now: f64) -> bool {
80            crate::rotation::lower::ops::eval_aura_refreshable(
81                &mut crate::rotation::lower::ops::ScalarEvalOps,
82                self.expires_at,
83                self.base_duration,
84                now,
85            )
86        }
87
88        #[must_use]
89        pub fn is_ticking(&self) -> bool {
90            self.tick_interval > 0.0
91        }
92    }
93}