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