wowlab_engine_domain/rotation/buffer/
aura.rs1pub 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 pub base_tick_interval: f64,
33
34 pub time_rate_multiplier: f64,
36
37 #[expr("ticks_remaining", Int, Direct)]
38 pub remaining_ticks: i32,
39
40 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 pub snapshot_damage_mult: f64,
50 }
51
52 impl {
53 #[inline]
54 pub fn remove(&mut self) {
55 *self = Self::default();
56 }
57
58 #[inline]
60 #[must_use]
61 pub fn is_occupied(&self) -> bool {
62 self.expires_at > 0.0
63 }
64
65 #[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}
94
95#[derive(Clone, Copy, Debug)]
97pub struct AuraTransferState(AuraSlot);
98
99impl AuraTransferState {
100 #[must_use]
101 pub fn capture(slot: &AuraSlot) -> Option<Self> {
102 slot.is_occupied().then_some(Self(*slot))
103 }
104
105 #[must_use]
106 pub fn with_expiry(mut self, expires_at: f64) -> Self {
107 self.0.expires_at = expires_at;
108
109 self
110 }
111
112 #[must_use]
113 pub fn restart_ticks(mut self, now: f64, duration: f64) -> Self {
114 if self.0.tick_interval > 0.0 {
115 self.0.next_tick = now + self.0.tick_interval;
116 self.0.remaining_ticks =
117 wowlab_types::numeric::f64_to_i32_saturating_ceil(duration / self.0.tick_interval);
118 }
119
120 self
121 }
122
123 #[must_use]
124 pub const fn stacks(self) -> i32 {
125 self.0.stacks
126 }
127
128 #[must_use]
129 pub const fn expires_at(self) -> f64 {
130 self.0.expires_at
131 }
132
133 #[must_use]
134 pub const fn next_tick(self) -> f64 {
135 self.0.next_tick
136 }
137
138 #[must_use]
139 pub const fn tick_interval(self) -> f64 {
140 self.0.tick_interval
141 }
142
143 pub(super) const fn slot(self) -> AuraSlot {
144 self.0
145 }
146}