Skip to main content

leafwing_abilities/
premade_pools.rs

1//! Convenient premade resource [`Pool`] types to get you started.
2//!
3//! These can be annoying due to orphan rules that prevent you from implementing your own methods,
4//! so feel free to copy-paste them (without attribution) into your own source to make new variants.
5
6use crate::pool::{MaxPoolLessThanMin, Pool};
7use bevy::prelude::Component;
8use core::fmt::{Display, Formatter};
9use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
10use derive_more::{Add, AddAssign, Sub, SubAssign};
11
12/// A premade resource pool for life (aka health, hit points or HP).
13pub mod life {
14    use bevy::reflect::Reflect;
15
16    use crate::pool::RegeneratingPool;
17
18    use super::*;
19
20    /// The amount of life available to a unit.
21    /// If they lose it all, they die or pass out.
22    ///
23    /// This is intended to be stored as a component on each entity.
24    #[derive(Debug, Clone, PartialEq, Component, Reflect)]
25    pub struct LifePool {
26        /// The current life.
27        current: Life,
28        /// The maximum life that can be stored.
29        max: Life,
30        /// The amount of life regenerated per second.
31        pub regen_per_second: Life,
32    }
33
34    impl LifePool {
35        /// Creates a new [`LifePool`] with the supplied settings.
36        ///
37        /// # Panics
38        /// Panics if `current` is greater than `max`.
39        /// Panics if `current` or max is negative.
40        pub fn new(current: Life, max: Life, regen_per_second: Life) -> Self {
41            assert!(current <= max);
42            assert!(current >= LifePool::MIN);
43            assert!(max >= LifePool::MIN);
44            Self {
45                current,
46                max,
47                regen_per_second,
48            }
49        }
50    }
51
52    /// A quantity of life, used to modify a [`LifePool`].
53    ///
54    /// This can be used for damage computations, life regeneration, healing and so on.
55    #[derive(
56        Debug, Clone, Copy, PartialEq, PartialOrd, Default, Add, Sub, AddAssign, SubAssign, Reflect,
57    )]
58    pub struct Life(pub f32);
59
60    impl Mul<f32> for Life {
61        type Output = Life;
62
63        fn mul(self, rhs: f32) -> Life {
64            Life(self.0 * rhs)
65        }
66    }
67
68    impl Mul<Life> for f32 {
69        type Output = Life;
70
71        fn mul(self, rhs: Life) -> Life {
72            Life(self * rhs.0)
73        }
74    }
75
76    impl Div<f32> for Life {
77        type Output = Life;
78
79        fn div(self, rhs: f32) -> Life {
80            Life(self.0 / rhs)
81        }
82    }
83
84    impl Div<Life> for Life {
85        type Output = f32;
86
87        fn div(self, rhs: Life) -> f32 {
88            self.0 / rhs.0
89        }
90    }
91
92    impl Pool for LifePool {
93        type Quantity = Life;
94        const MIN: Life = Life(0.);
95
96        fn current(&self) -> Self::Quantity {
97            self.current
98        }
99
100        fn set_current(&mut self, new_quantity: Self::Quantity) -> Self::Quantity {
101            let actual_value = Life(new_quantity.0.clamp(0., self.max.0));
102            self.current = actual_value;
103            self.current
104        }
105
106        fn max(&self) -> Self::Quantity {
107            self.max
108        }
109
110        fn set_max(&mut self, new_max: Self::Quantity) -> Result<(), MaxPoolLessThanMin> {
111            if new_max < Self::MIN {
112                Err(MaxPoolLessThanMin)
113            } else {
114                self.max = new_max;
115                self.set_current(self.current);
116                Ok(())
117            }
118        }
119    }
120
121    impl RegeneratingPool for LifePool {
122        fn regen_per_second(&self) -> Self::Quantity {
123            self.regen_per_second
124        }
125
126        fn set_regen_per_second(&mut self, new_regen_per_second: Self::Quantity) {
127            self.regen_per_second = new_regen_per_second;
128        }
129
130        fn regenerate(&mut self, delta_time: std::time::Duration) {
131            self.set_current(self.current + self.regen_per_second * delta_time.as_secs_f32());
132        }
133    }
134
135    impl Add<Life> for LifePool {
136        type Output = Self;
137
138        fn add(mut self, rhs: Life) -> Self::Output {
139            self.set_current(self.current + rhs);
140            self
141        }
142    }
143
144    impl Sub<Life> for LifePool {
145        type Output = Self;
146
147        fn sub(mut self, rhs: Life) -> Self::Output {
148            self.set_current(self.current - rhs);
149            self
150        }
151    }
152
153    impl AddAssign<Life> for LifePool {
154        fn add_assign(&mut self, rhs: Life) {
155            self.set_current(self.current + rhs);
156        }
157    }
158
159    impl SubAssign<Life> for LifePool {
160        fn sub_assign(&mut self, rhs: Life) {
161            self.set_current(self.current - rhs);
162        }
163    }
164
165    impl Display for Life {
166        fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
167            write!(f, "{}", self.0)
168        }
169    }
170
171    impl Display for LifePool {
172        fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
173            write!(f, "{}/{}", self.current, self.max)
174        }
175    }
176}
177
178/// A premade resource pool for mana (aka MP).
179pub mod mana {
180    use bevy::reflect::Reflect;
181
182    use crate::pool::RegeneratingPool;
183
184    use super::*;
185
186    /// The amount of mana available to a unit.
187    /// Units must spend mana to cast spells according to their [`AbilityCosts<A, Mana>`](crate::pool::AbilityCosts) component.
188    ///
189    /// This is intended to be stored as a component on each entity.
190    #[derive(Debug, Clone, PartialEq, Component, Reflect)]
191    pub struct ManaPool {
192        /// The current mana.
193        current: Mana,
194        /// The maximum mana that can be stored.
195        max: Mana,
196        /// The amount of mana regenerated per second.
197        pub regen_per_second: Mana,
198    }
199
200    impl ManaPool {
201        /// Creates a new [`ManaPool`] with the supplied settings.
202        ///
203        /// # Panics
204        /// Panics if `current` is greater than `max`.
205        /// Panics if `current` or `max` is negative.
206        pub fn new(current: Mana, max: Mana, regen_per_second: Mana) -> Self {
207            assert!(current <= max);
208            assert!(current >= ManaPool::MIN);
209            assert!(max >= ManaPool::MIN);
210            Self {
211                current,
212                max,
213                regen_per_second,
214            }
215        }
216    }
217
218    /// A quantity of mana, used to modify a [`ManaPool`].
219    ///
220    /// This can be used for ability costs, mana regeneration and so on.
221    #[derive(
222        Debug, Clone, Copy, PartialEq, PartialOrd, Default, Add, Sub, AddAssign, SubAssign, Reflect,
223    )]
224    pub struct Mana(pub f32);
225
226    impl Mul<f32> for Mana {
227        type Output = Mana;
228
229        fn mul(self, rhs: f32) -> Mana {
230            Mana(self.0 * rhs)
231        }
232    }
233
234    impl Mul<Mana> for f32 {
235        type Output = Mana;
236
237        fn mul(self, rhs: Mana) -> Mana {
238            Mana(self * rhs.0)
239        }
240    }
241
242    impl Div<f32> for Mana {
243        type Output = Mana;
244
245        fn div(self, rhs: f32) -> Mana {
246            Mana(self.0 / rhs)
247        }
248    }
249
250    impl Div<Mana> for Mana {
251        type Output = f32;
252
253        fn div(self, rhs: Mana) -> f32 {
254            self.0 / rhs.0
255        }
256    }
257
258    impl Pool for ManaPool {
259        type Quantity = Mana;
260        const MIN: Mana = Mana(0.);
261
262        fn current(&self) -> Self::Quantity {
263            self.current
264        }
265
266        fn set_current(&mut self, new_quantity: Self::Quantity) -> Self::Quantity {
267            let actual_value = Mana(new_quantity.0.clamp(0., self.max.0));
268            self.current = actual_value;
269            self.current
270        }
271
272        fn max(&self) -> Self::Quantity {
273            self.max
274        }
275
276        fn set_max(&mut self, new_max: Self::Quantity) -> Result<(), MaxPoolLessThanMin> {
277            if new_max < Self::MIN {
278                Err(MaxPoolLessThanMin)
279            } else {
280                self.max = new_max;
281                self.set_current(self.current);
282                Ok(())
283            }
284        }
285    }
286
287    impl RegeneratingPool for ManaPool {
288        fn regen_per_second(&self) -> Self::Quantity {
289            self.regen_per_second
290        }
291
292        fn set_regen_per_second(&mut self, new_regen_per_second: Self::Quantity) {
293            self.regen_per_second = new_regen_per_second;
294        }
295
296        fn regenerate(&mut self, delta_time: std::time::Duration) {
297            self.set_current(self.current + self.regen_per_second * delta_time.as_secs_f32());
298        }
299    }
300
301    impl Add<Mana> for ManaPool {
302        type Output = Self;
303
304        fn add(mut self, rhs: Mana) -> Self::Output {
305            self.set_current(self.current + rhs);
306            self
307        }
308    }
309
310    impl Sub<Mana> for ManaPool {
311        type Output = Self;
312
313        fn sub(mut self, rhs: Mana) -> Self::Output {
314            self.set_current(self.current - rhs);
315            self
316        }
317    }
318
319    impl AddAssign<Mana> for ManaPool {
320        fn add_assign(&mut self, rhs: Mana) {
321            self.set_current(self.current + rhs);
322        }
323    }
324
325    impl SubAssign<Mana> for ManaPool {
326        fn sub_assign(&mut self, rhs: Mana) {
327            self.set_current(self.current - rhs);
328        }
329    }
330
331    impl Display for Mana {
332        fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
333            write!(f, "{}", self.0)
334        }
335    }
336
337    impl Display for ManaPool {
338        fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
339            write!(f, "{}/{}", self.current, self.max)
340        }
341    }
342}