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