Skip to main content

nil_core/resources/
maintenance.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use super::Food;
5use super::diff::FoodDiff;
6use crate::military::unit::UnitChunkSize;
7use derive_more::{Deref, Display, Into};
8use serde::{Deserialize, Serialize};
9use std::cmp::Ordering;
10use std::num::NonZeroU32;
11use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
12
13/// Maintenance tax of an entity.
14///
15/// Its value is equivalent to a percentage of the [base cost].
16///
17/// [base cost]: crate::resources::cost::Cost
18#[derive(
19  Clone,
20  Copy,
21  Debug,
22  Default,
23  Deref,
24  Display,
25  Into,
26  Deserialize,
27  Serialize,
28  PartialEq,
29  Eq,
30  PartialOrd,
31  Ord,
32)]
33#[into(u32, f64, Food)]
34pub struct Maintenance(Food);
35
36impl Maintenance {
37  #[inline]
38  pub const fn new(value: u32) -> Self {
39    Self(Food::new(value))
40  }
41}
42
43impl From<u32> for Maintenance {
44  fn from(value: u32) -> Self {
45    Self::new(value)
46  }
47}
48
49impl From<f64> for Maintenance {
50  fn from(value: f64) -> Self {
51    debug_assert!(value.is_finite());
52    Self::new(value as u32)
53  }
54}
55
56impl Add for Maintenance {
57  type Output = Self;
58
59  fn add(self, rhs: Self) -> Self {
60    Self(self.0 + rhs.0)
61  }
62}
63
64impl Add<Food> for Maintenance {
65  type Output = Self;
66
67  fn add(self, rhs: Food) -> Self {
68    Self(self.0 + rhs)
69  }
70}
71
72impl AddAssign for Maintenance {
73  fn add_assign(&mut self, rhs: Self) {
74    *self = Self(self.0 + rhs.0);
75  }
76}
77
78impl AddAssign<Food> for Maintenance {
79  fn add_assign(&mut self, rhs: Food) {
80    *self = Self(self.0 + rhs);
81  }
82}
83
84impl Sub for Maintenance {
85  type Output = Self;
86
87  fn sub(self, rhs: Self) -> Self {
88    Self(self.0 - rhs.0)
89  }
90}
91
92impl Sub<Food> for Maintenance {
93  type Output = Self;
94
95  fn sub(self, rhs: Food) -> Self {
96    Self(self.0 - rhs)
97  }
98}
99
100impl Sub<Maintenance> for Food {
101  type Output = Self;
102
103  fn sub(self, rhs: Maintenance) -> Self {
104    self - rhs.0
105  }
106}
107
108impl Sub<Maintenance> for FoodDiff {
109  type Output = Self;
110
111  fn sub(self, rhs: Maintenance) -> Self {
112    self - rhs.0
113  }
114}
115
116impl SubAssign for Maintenance {
117  fn sub_assign(&mut self, rhs: Self) {
118    *self = Self(self.0 - rhs.0);
119  }
120}
121
122impl SubAssign<Food> for Maintenance {
123  fn sub_assign(&mut self, rhs: Food) {
124    *self = Self(self.0 - rhs);
125  }
126}
127
128impl SubAssign<Maintenance> for Food {
129  fn sub_assign(&mut self, rhs: Maintenance) {
130    *self = *self - rhs.0;
131  }
132}
133
134impl SubAssign<Maintenance> for FoodDiff {
135  fn sub_assign(&mut self, rhs: Maintenance) {
136    *self = *self - rhs.0;
137  }
138}
139
140impl Mul<u32> for Maintenance {
141  type Output = Maintenance;
142
143  fn mul(self, rhs: u32) -> Self::Output {
144    Self(self.0 * rhs)
145  }
146}
147
148impl Mul<NonZeroU32> for Maintenance {
149  type Output = Maintenance;
150
151  fn mul(self, rhs: NonZeroU32) -> Self::Output {
152    Self(self.0 * rhs.get())
153  }
154}
155
156impl Div<UnitChunkSize> for Maintenance {
157  type Output = Maintenance;
158
159  fn div(self, rhs: UnitChunkSize) -> Self::Output {
160    let maintenance = f64::from(self);
161    let chunk_size = f64::from(rhs);
162    Self::from(maintenance / chunk_size)
163  }
164}
165
166impl PartialEq<Food> for Maintenance {
167  fn eq(&self, other: &Food) -> bool {
168    self.0.eq(other)
169  }
170}
171
172impl PartialEq<Maintenance> for Food {
173  fn eq(&self, other: &Maintenance) -> bool {
174    self.eq(&other.0)
175  }
176}
177
178impl PartialOrd<Food> for Maintenance {
179  fn partial_cmp(&self, other: &Food) -> Option<Ordering> {
180    self.0.partial_cmp(other)
181  }
182}
183
184impl PartialOrd<Maintenance> for Food {
185  fn partial_cmp(&self, other: &Maintenance) -> Option<Ordering> {
186    self.partial_cmp(&other.0)
187  }
188}
189
190/// Proportion of the base cost that should be used as a maintenance tax.
191#[derive(Clone, Copy, Debug, Deref, Into, Deserialize, Serialize)]
192pub struct MaintenanceRatio(f64);
193
194impl MaintenanceRatio {
195  #[inline]
196  pub const fn new(ratio: f64) -> Self {
197    debug_assert!(ratio.is_finite());
198    debug_assert!(!ratio.is_subnormal());
199    Self(ratio.clamp(0.0, 1.0))
200  }
201}
202
203#[derive(Clone, Debug, Deserialize, Serialize)]
204#[serde(rename_all = "camelCase")]
205pub struct MaintenanceBalance {
206  pub maintenance: Maintenance,
207  pub production: Food,
208}
209
210impl MaintenanceBalance {
211  /// Checks if the food production is enough to cover the maintenance costs.
212  #[inline]
213  pub fn is_sustainable(&self) -> bool {
214    self.production >= self.maintenance
215  }
216}
217
218impl Add<Maintenance> for MaintenanceBalance {
219  type Output = Self;
220
221  fn add(self, rhs: Maintenance) -> Self::Output {
222    Self {
223      maintenance: self.maintenance + rhs,
224      production: self.production,
225    }
226  }
227}