nil_core/military/unit/stats/
power.rs1use crate::military::army::Army;
5use crate::military::army::personnel::ArmyPersonnel;
6use crate::military::squad::Squad;
7use crate::military::squad::size::SquadSize;
8use crate::military::unit::stats::ranged_debuff::RangedDebuff;
9use bon::Builder;
10use derive_more::Display;
11use nil_util::{ConstDeref, F64Math};
12use serde::{Deserialize, Serialize};
13use std::iter::Sum;
14use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Sub};
15
16#[derive(Copy, Debug, Display, Deserialize, Serialize, ConstDeref, F64Math)]
17#[derive_const(Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
18#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
19pub struct Power(u32);
20
21impl Power {
22 #[inline]
23 pub const fn new(value: u32) -> Self {
24 Self(value)
25 }
26}
27
28const impl From<u32> for Power {
29 fn from(value: u32) -> Self {
30 Power::new(value)
31 }
32}
33
34const impl From<Power> for u32 {
35 fn from(value: Power) -> Self {
36 value.0
37 }
38}
39
40const impl From<Power> for f64 {
41 fn from(value: Power) -> Self {
42 f64::from(value.0)
43 }
44}
45
46impl<'a> Sum<&'a Squad> for Power {
47 fn sum<I>(iter: I) -> Self
48 where
49 I: Iterator<Item = &'a Squad>,
50 {
51 iter.fold(Power::default(), |mut acc, squad| {
52 acc += squad.power();
53 acc
54 })
55 }
56}
57
58impl<'a> Sum<&'a ArmyPersonnel> for Power {
59 fn sum<I>(iter: I) -> Self
60 where
61 I: Iterator<Item = &'a ArmyPersonnel>,
62 {
63 iter.flat_map(ArmyPersonnel::iter).sum()
64 }
65}
66
67impl<'a> Sum<&'a Army> for Power {
68 fn sum<I>(iter: I) -> Self
69 where
70 I: Iterator<Item = &'a Army>,
71 {
72 iter.flat_map(Army::iter).sum()
73 }
74}
75
76const impl Add for Power {
77 type Output = Power;
78
79 fn add(self, rhs: Self) -> Self::Output {
80 Self(self.0.saturating_add(rhs.0))
81 }
82}
83
84const impl AddAssign for Power {
85 fn add_assign(&mut self, rhs: Self) {
86 *self = *self + rhs;
87 }
88}
89
90const impl Sub for Power {
91 type Output = Power;
92
93 fn sub(self, rhs: Self) -> Self::Output {
94 Self(self.0.saturating_sub(rhs.0))
95 }
96}
97
98const impl Mul for Power {
99 type Output = Power;
100
101 fn mul(self, rhs: Self) -> Self::Output {
102 Self(self.0.saturating_mul(rhs.0))
103 }
104}
105
106const impl Mul<u32> for Power {
107 type Output = Power;
108
109 fn mul(self, rhs: u32) -> Self::Output {
110 Self(self.0.saturating_mul(rhs))
111 }
112}
113
114const impl Mul<Power> for u32 {
115 type Output = u32;
116
117 fn mul(self, rhs: Power) -> Self::Output {
118 self.saturating_mul(rhs.0)
119 }
120}
121
122const impl Mul<RangedDebuff> for Power {
123 type Output = f64;
124
125 fn mul(self, rhs: RangedDebuff) -> Self::Output {
126 f64::from(self.0) * rhs
127 }
128}
129
130const impl Mul<SquadSize> for Power {
131 type Output = Power;
132
133 fn mul(self, rhs: SquadSize) -> Self::Output {
134 self * u32::from(rhs)
135 }
136}
137
138const impl MulAssign<u32> for Power {
139 fn mul_assign(&mut self, rhs: u32) {
140 *self = *self * rhs;
141 }
142}
143
144const impl MulAssign<SquadSize> for Power {
145 fn mul_assign(&mut self, rhs: SquadSize) {
146 *self = *self * rhs;
147 }
148}
149
150const impl Div for Power {
151 type Output = Power;
152
153 fn div(self, rhs: Self) -> Self::Output {
154 Self(self.0.saturating_div(rhs.0))
155 }
156}
157
158const impl Div<u32> for Power {
159 type Output = Power;
160
161 fn div(self, rhs: u32) -> Self::Output {
162 Self(self.0.saturating_div(rhs))
163 }
164}
165
166const impl Div<Power> for u32 {
167 type Output = u32;
168
169 fn div(self, rhs: Power) -> Self::Output {
170 self.saturating_div(rhs.0)
171 }
172}
173
174#[derive(Copy, Debug, Deserialize, Serialize, ConstDeref, F64Math)]
175#[derive_const(Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
176#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
177pub struct AttackPower(Power);
178
179impl AttackPower {
180 pub const fn new<P>(value: P) -> Self
181 where
182 P: [const] Into<Power>,
183 {
184 Self(value.into())
185 }
186}
187
188const impl From<u32> for AttackPower {
189 fn from(value: u32) -> Self {
190 Self(Power::new(value))
191 }
192}
193
194const impl From<AttackPower> for f64 {
195 fn from(value: AttackPower) -> Self {
196 f64::from(value.0)
197 }
198}
199
200impl<'a> Sum<&'a Squad> for AttackPower {
201 fn sum<I>(iter: I) -> Self
202 where
203 I: Iterator<Item = &'a Squad>,
204 {
205 iter.fold(AttackPower::default(), |mut acc, squad| {
206 acc += squad.attack();
207 acc
208 })
209 }
210}
211
212impl<'a> Sum<&'a ArmyPersonnel> for AttackPower {
213 fn sum<I>(iter: I) -> Self
214 where
215 I: Iterator<Item = &'a ArmyPersonnel>,
216 {
217 iter.flat_map(ArmyPersonnel::iter).sum()
218 }
219}
220
221impl<'a> Sum<&'a Army> for AttackPower {
222 fn sum<I>(iter: I) -> Self
223 where
224 I: Iterator<Item = &'a Army>,
225 {
226 iter.flat_map(Army::iter).sum()
227 }
228}
229
230impl Add for AttackPower {
231 type Output = AttackPower;
232
233 fn add(self, rhs: Self) -> Self::Output {
234 Self(self.0 + rhs.0)
235 }
236}
237
238impl AddAssign for AttackPower {
239 fn add_assign(&mut self, rhs: Self) {
240 *self = *self + rhs;
241 }
242}
243
244const impl Mul<u32> for AttackPower {
245 type Output = AttackPower;
246
247 fn mul(self, rhs: u32) -> Self::Output {
248 Self(self.0 * rhs)
249 }
250}
251
252const impl Mul<RangedDebuff> for AttackPower {
253 type Output = f64;
254
255 fn mul(self, rhs: RangedDebuff) -> Self::Output {
256 self.0 * rhs
257 }
258}
259
260const impl Mul<SquadSize> for AttackPower {
261 type Output = AttackPower;
262
263 fn mul(self, rhs: SquadSize) -> Self::Output {
264 Self(self.0 * rhs)
265 }
266}
267
268#[derive(Copy, Builder, Debug, Deserialize, Serialize)]
269#[derive_const(Clone, Default, PartialEq, Eq)]
270#[builder(const)]
271#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
272pub struct DefensePower {
273 pub(crate) cavalry: Power,
274 pub(crate) infantry: Power,
275 pub(crate) ranged: Power,
276}
277
278impl DefensePower {
279 #[inline]
280 pub const fn cavalry(&self) -> Power {
281 self.cavalry
282 }
283
284 #[inline]
285 pub const fn infantry(&self) -> Power {
286 self.infantry
287 }
288
289 #[inline]
290 pub const fn ranged(&self) -> Power {
291 self.ranged
292 }
293
294 pub const fn mean(&self) -> Power {
295 let defense = 0u32
296 .saturating_add(*self.cavalry)
297 .saturating_add(*self.infantry)
298 .saturating_add(*self.ranged);
299
300 Power::new(defense / 3)
301 }
302}
303
304impl<'a> Sum<&'a Squad> for DefensePower {
305 fn sum<I>(iter: I) -> Self
306 where
307 I: Iterator<Item = &'a Squad>,
308 {
309 iter.fold(DefensePower::default(), |mut acc, squad| {
310 acc += squad.defense();
311 acc
312 })
313 }
314}
315
316impl<'a> Sum<&'a ArmyPersonnel> for DefensePower {
317 fn sum<I>(iter: I) -> Self
318 where
319 I: Iterator<Item = &'a ArmyPersonnel>,
320 {
321 iter.flat_map(ArmyPersonnel::iter).sum()
322 }
323}
324
325impl<'a> Sum<&'a Army> for DefensePower {
326 fn sum<I>(iter: I) -> Self
327 where
328 I: Iterator<Item = &'a Army>,
329 {
330 iter.flat_map(Army::iter).sum()
331 }
332}
333
334const impl Add for DefensePower {
335 type Output = DefensePower;
336
337 fn add(mut self, rhs: Self) -> Self::Output {
338 self.cavalry += rhs.cavalry;
339 self.infantry += rhs.infantry;
340 self.ranged += rhs.ranged;
341 self
342 }
343}
344
345const impl AddAssign for DefensePower {
346 fn add_assign(&mut self, rhs: Self) {
347 *self = *self + rhs;
348 }
349}
350
351const impl Mul<u32> for DefensePower {
352 type Output = DefensePower;
353
354 fn mul(mut self, rhs: u32) -> Self::Output {
355 self.cavalry *= rhs;
356 self.infantry *= rhs;
357 self.ranged *= rhs;
358 self
359 }
360}
361
362const impl Mul<SquadSize> for DefensePower {
363 type Output = DefensePower;
364
365 fn mul(self, rhs: SquadSize) -> Self::Output {
366 self * u32::from(rhs)
367 }
368}
369
370const impl MulAssign<u32> for DefensePower {
371 fn mul_assign(&mut self, rhs: u32) {
372 *self = *self * rhs;
373 }
374}
375
376const impl MulAssign<SquadSize> for DefensePower {
377 fn mul_assign(&mut self, rhs: SquadSize) {
378 *self = *self * rhs;
379 }
380}