wowlab_engine_domain/rotation/buffer/
resource.rs1wowlab_engine_macros::define_slot! {
2 #[slot(domain = "resource", kind = keyed, key_domain = "resource")]
3 pub struct ResourceSlot {
4 #[expr("current", Float, Direct)]
5 #[expr("deficit", Float, ResourceDeficit)]
6 #[expr("pct", Float, ResourcePct)]
7 #[expr("deficit_pct", Float, ResourceDeficitPct)]
8 #[expr("time_to_max", Float, ResourceTimeToMax)]
9 pub current: f64,
10
11 #[expr("max", Float, Direct)]
12 pub max: f64,
13
14 #[expr("regen", Float, Direct)]
15 pub regen_per_sec: f64,
16 }
17
18 impl {
19 #[inline]
20 pub fn spend(&mut self, amount: f64) -> bool {
21 if self.current < amount {
22 return false;
23 }
24 self.current -= amount;
25 true
26 }
27
28 #[inline]
29 pub fn gain(&mut self, amount: f64) -> f64 {
31 let new = (self.current + amount).min(self.max);
32 let actual = new - self.current;
33 self.current = new;
34 amount - actual
35 }
36 #[must_use]
39 pub fn deficit(&self) -> f64 {
40 crate::rotation::lower::ops::eval_resource_deficit(
41 &mut crate::rotation::lower::ops::ScalarEvalOps,
42 self.current,
43 self.max,
44 )
45 }
46
47 #[must_use]
48 pub fn pct(&self) -> f64 {
49 crate::rotation::lower::ops::eval_resource_pct(
50 &mut crate::rotation::lower::ops::ScalarEvalOps,
51 self.current,
52 self.max,
53 )
54 }
55
56 #[must_use]
57 pub fn deficit_pct(&self) -> f64 {
58 crate::rotation::lower::ops::eval_resource_deficit_pct(
59 &mut crate::rotation::lower::ops::ScalarEvalOps,
60 self.current,
61 self.max,
62 )
63 }
64
65 #[must_use]
66 pub fn time_to_max(&self) -> f64 {
67 crate::rotation::lower::ops::eval_resource_time_to_max(
68 &mut crate::rotation::lower::ops::ScalarEvalOps,
69 self.current,
70 self.max,
71 self.regen_per_sec,
72 )
73 }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use googletest::prelude::*;
80
81 use super::*;
82
83 #[gtest]
84 fn gain_returns_overflow_above_cap() -> Result<()> {
85 let mut slot = ResourceSlot {
86 current: 600.0,
87 max: 1000.0,
88 ..Default::default()
89 };
90 let overflow = slot.gain(500.0);
91
92 verify_that!(overflow, near(100.0, 1e-9))?;
93
94 verify_that!(slot.current, near(1000.0, 1e-9))
95 }
96
97 #[gtest]
98 fn gain_returns_zero_under_cap() -> Result<()> {
99 let mut slot = ResourceSlot {
100 current: 600.0,
101 max: 1000.0,
102 ..Default::default()
103 };
104 let overflow = slot.gain(200.0);
105
106 verify_that!(overflow, near(0.0, 1e-9))?;
107
108 verify_that!(slot.current, near(800.0, 1e-9))
109 }
110
111 #[gtest]
112 fn spend_rejects_insufficient_and_leaves_current() -> Result<()> {
113 let mut slot = ResourceSlot {
114 current: 100.0,
115 ..Default::default()
116 };
117
118 verify_that!(slot.spend(150.0), eq(false))?;
119
120 verify_that!(slot.current, near(100.0, 1e-9))
121 }
122
123 #[gtest]
124 fn spend_deducts_when_affordable() -> Result<()> {
125 let mut slot = ResourceSlot {
126 current: 100.0,
127 ..Default::default()
128 };
129
130 verify_that!(slot.spend(40.0), eq(true))?;
131
132 verify_that!(slot.current, near(60.0, 1e-9))
133 }
134}