Skip to main content

nil_core/military/unit/stats/
power.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use 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}