Skip to main content

nil_core/military/squad/
mod.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4pub mod size;
5
6use crate::error::{Error, Result};
7use crate::military::unit::stats::haul::Haul;
8use crate::military::unit::stats::power::{AttackPower, DefensePower, Power};
9use crate::military::unit::stats::speed::Speed;
10use crate::military::unit::{Unit, UnitBox, UnitId, UnitKind};
11use crate::ranking::score::Score;
12use crate::resources::maintenance::Maintenance;
13use crate::world::config::WorldConfig;
14use serde::{Deserialize, Serialize};
15use size::SquadSize;
16use std::fmt;
17use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
18
19/// A group of units of the same type.
20#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
21#[serde(rename_all = "camelCase")]
22#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
23pub struct Squad {
24  unit: UnitBox,
25  size: SquadSize,
26}
27
28impl Squad {
29  pub fn new(id: UnitId, size: impl Into<SquadSize>) -> Self {
30    Self {
31      unit: UnitBox::from(id),
32      size: size.into(),
33    }
34  }
35
36  #[inline]
37  pub fn unit(&self) -> &dyn Unit {
38    self.unit.as_dyn()
39  }
40
41  #[inline]
42  pub fn id(&self) -> UnitId {
43    self.unit.id()
44  }
45
46  #[inline]
47  pub fn kind(&self) -> UnitKind {
48    self.unit.kind()
49  }
50
51  #[inline]
52  pub fn size(&self) -> SquadSize {
53    self.size
54  }
55
56  #[inline]
57  pub fn score(&self) -> Score {
58    self.size * self.unit.score()
59  }
60
61  #[inline]
62  pub fn is_empty(&self) -> bool {
63    self.size == 0u32
64  }
65
66  pub fn maintenance(&self) -> Maintenance {
67    let chunk = self.unit.chunk();
68    let c_size = chunk.size();
69    let c_maintenance = chunk.maintenance();
70    (self.size() * c_maintenance) / c_size
71  }
72
73  /// Average power of the squad.
74  #[inline]
75  pub fn power(&self) -> Power {
76    self.unit.power() * self.size
77  }
78
79  #[inline]
80  pub fn attack(&self) -> AttackPower {
81    self.unit.attack() * self.size
82  }
83
84  #[inline]
85  pub fn defense(&self) -> DefensePower {
86    self.unit.defense() * self.size
87  }
88
89  #[inline]
90  pub fn speed(&self, config: &WorldConfig) -> Speed {
91    self.unit.speed(config)
92  }
93
94  #[inline]
95  pub fn haul(&self) -> Haul {
96    self.unit.haul() * self.size
97  }
98
99  pub fn checked_sub(&self, rhs: &Self) -> Result<Option<Self>> {
100    if self.unit == rhs.unit {
101      Ok(try { Self::new(self.id(), self.size.checked_sub(rhs.size)?) })
102    } else {
103      Err(Error::UnexpectedUnit(self.id(), rhs.id()))
104    }
105  }
106}
107
108impl fmt::Display for Squad {
109  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110    write!(f, "{} ({})", self.unit, self.size)
111  }
112}
113
114impl From<UnitId> for Squad {
115  fn from(id: UnitId) -> Self {
116    Squad::new(id, SquadSize::new(0))
117  }
118}
119
120impl Add for Squad {
121  type Output = Squad;
122
123  fn add(mut self, rhs: Self) -> Self::Output {
124    self += rhs;
125    self
126  }
127}
128
129impl Add<SquadSize> for Squad {
130  type Output = Squad;
131
132  fn add(mut self, rhs: SquadSize) -> Self::Output {
133    self += rhs;
134    self
135  }
136}
137
138impl AddAssign for Squad {
139  fn add_assign(&mut self, rhs: Self) {
140    if self.id() == rhs.id() {
141      self.size += rhs.size;
142    }
143  }
144}
145
146impl AddAssign<SquadSize> for Squad {
147  fn add_assign(&mut self, rhs: SquadSize) {
148    self.size += rhs;
149  }
150}
151
152impl Sub for Squad {
153  type Output = Squad;
154
155  fn sub(mut self, rhs: Self) -> Self::Output {
156    self -= rhs;
157    self
158  }
159}
160
161impl Sub<SquadSize> for Squad {
162  type Output = Squad;
163
164  fn sub(mut self, rhs: SquadSize) -> Self::Output {
165    self -= rhs;
166    self
167  }
168}
169
170impl SubAssign for Squad {
171  fn sub_assign(&mut self, rhs: Self) {
172    if self.id() == rhs.id() {
173      self.size -= rhs.size;
174    }
175  }
176}
177
178impl SubAssign<SquadSize> for Squad {
179  fn sub_assign(&mut self, rhs: SquadSize) {
180    self.size -= rhs;
181  }
182}
183
184impl Mul<f64> for Squad {
185  type Output = Squad;
186
187  fn mul(mut self, rhs: f64) -> Self::Output {
188    self *= rhs;
189    self
190  }
191}
192
193impl MulAssign<f64> for Squad {
194  fn mul_assign(&mut self, rhs: f64) {
195    self.size *= rhs;
196  }
197}