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