Skip to main content

nil_core/infrastructure/building/
level.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use derive_more::{Deref, Into};
5use nil_util::F64Math;
6use serde::{Deserialize, Serialize};
7use std::cmp;
8use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
9
10#[derive(Copy, Debug, Deref, derive_more::Display, Into, Hash, Deserialize, Serialize, F64Math)]
11#[derive_const(Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
12#[into(i16, i32, u8, u16, u64, usize)]
13#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
14pub struct BuildingLevel(u8);
15
16impl BuildingLevel {
17  pub const ZERO: BuildingLevel = BuildingLevel(0);
18
19  #[inline]
20  pub const fn new(level: u8) -> Self {
21    Self(level)
22  }
23}
24
25impl const From<BuildingLevel> for i8 {
26  fn from(value: BuildingLevel) -> Self {
27    debug_assert!(i8::try_from(value.0).is_ok());
28    i8::try_from(value.0).unwrap_or(i8::MAX)
29  }
30}
31
32impl const From<BuildingLevel> for u32 {
33  fn from(value: BuildingLevel) -> Self {
34    u32::from(value.0)
35  }
36}
37
38impl const From<BuildingLevel> for f64 {
39  fn from(value: BuildingLevel) -> Self {
40    f64::from(value.0)
41  }
42}
43
44impl const PartialEq<u8> for BuildingLevel {
45  fn eq(&self, other: &u8) -> bool {
46    self.0.eq(other)
47  }
48}
49
50impl const PartialEq<BuildingLevel> for u8 {
51  fn eq(&self, other: &BuildingLevel) -> bool {
52    self.eq(&other.0)
53  }
54}
55
56impl const PartialEq<f64> for BuildingLevel {
57  fn eq(&self, other: &f64) -> bool {
58    f64::from(self.0).eq(other)
59  }
60}
61
62impl const PartialEq<BuildingLevel> for f64 {
63  fn eq(&self, other: &BuildingLevel) -> bool {
64    self.eq(&f64::from(other.0))
65  }
66}
67
68impl const PartialOrd<u8> for BuildingLevel {
69  fn partial_cmp(&self, other: &u8) -> Option<cmp::Ordering> {
70    self.0.partial_cmp(other)
71  }
72}
73
74impl const PartialOrd<BuildingLevel> for u8 {
75  fn partial_cmp(&self, other: &BuildingLevel) -> Option<cmp::Ordering> {
76    self.partial_cmp(&other.0)
77  }
78}
79
80impl const PartialOrd<f64> for BuildingLevel {
81  fn partial_cmp(&self, other: &f64) -> Option<cmp::Ordering> {
82    f64::from(self.0).partial_cmp(other)
83  }
84}
85
86impl const PartialOrd<BuildingLevel> for f64 {
87  fn partial_cmp(&self, other: &BuildingLevel) -> Option<cmp::Ordering> {
88    self.partial_cmp(&f64::from(other.0))
89  }
90}
91
92impl const Add for BuildingLevel {
93  type Output = Self;
94
95  fn add(self, rhs: Self) -> Self {
96    Self(self.0.saturating_add(rhs.0))
97  }
98}
99
100impl const Add<u8> for BuildingLevel {
101  type Output = Self;
102
103  fn add(self, rhs: u8) -> Self {
104    Self(self.0.saturating_add(rhs))
105  }
106}
107
108impl const Add<i8> for BuildingLevel {
109  type Output = Self;
110
111  fn add(self, rhs: i8) -> Self {
112    Self(self.0.saturating_add_signed(rhs))
113  }
114}
115
116impl const Add<BuildingLevelDiff> for BuildingLevel {
117  type Output = Self;
118
119  fn add(self, rhs: BuildingLevelDiff) -> Self {
120    self + rhs.0
121  }
122}
123
124impl const AddAssign for BuildingLevel {
125  fn add_assign(&mut self, rhs: Self) {
126    *self = *self + rhs;
127  }
128}
129
130impl const AddAssign<u8> for BuildingLevel {
131  fn add_assign(&mut self, rhs: u8) {
132    *self = *self + rhs;
133  }
134}
135
136impl const AddAssign<i8> for BuildingLevel {
137  fn add_assign(&mut self, rhs: i8) {
138    *self = *self + rhs;
139  }
140}
141
142impl const AddAssign<BuildingLevelDiff> for BuildingLevel {
143  fn add_assign(&mut self, rhs: BuildingLevelDiff) {
144    *self = *self + rhs;
145  }
146}
147
148impl const Sub for BuildingLevel {
149  type Output = Self;
150
151  fn sub(self, rhs: Self) -> Self {
152    Self(self.0.saturating_sub(rhs.0))
153  }
154}
155
156impl const Sub<u8> for BuildingLevel {
157  type Output = Self;
158
159  fn sub(self, rhs: u8) -> Self {
160    Self(self.0.saturating_sub(rhs))
161  }
162}
163
164impl const Sub<i8> for BuildingLevel {
165  type Output = Self;
166
167  fn sub(self, rhs: i8) -> Self {
168    Self(self.0.saturating_sub_signed(rhs))
169  }
170}
171
172impl const Sub<BuildingLevelDiff> for BuildingLevel {
173  type Output = Self;
174
175  fn sub(self, rhs: BuildingLevelDiff) -> Self {
176    self - rhs.0
177  }
178}
179
180impl const SubAssign for BuildingLevel {
181  fn sub_assign(&mut self, rhs: Self) {
182    *self = *self - rhs;
183  }
184}
185
186impl const SubAssign<u8> for BuildingLevel {
187  fn sub_assign(&mut self, rhs: u8) {
188    *self = *self - rhs;
189  }
190}
191
192impl const SubAssign<i8> for BuildingLevel {
193  fn sub_assign(&mut self, rhs: i8) {
194    *self = *self - rhs;
195  }
196}
197
198impl const SubAssign<BuildingLevelDiff> for BuildingLevel {
199  fn sub_assign(&mut self, rhs: BuildingLevelDiff) {
200    *self = *self - rhs;
201  }
202}
203
204impl const Neg for BuildingLevel {
205  type Output = BuildingLevelDiff;
206
207  fn neg(self) -> BuildingLevelDiff {
208    BuildingLevelDiff::new(i8::from(self).neg())
209  }
210}
211
212#[derive(Clone, Copy, Debug, Deref, derive_more::Display, Into, Hash, Deserialize, Serialize)]
213#[derive_const(Default, PartialEq, Eq, PartialOrd, Ord)]
214#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
215pub struct BuildingLevelDiff(i8);
216
217impl BuildingLevelDiff {
218  pub const ZERO: BuildingLevelDiff = BuildingLevelDiff(0);
219
220  #[inline]
221  pub const fn new(level_diff: i8) -> Self {
222    Self(level_diff)
223  }
224}
225
226impl const From<f64> for BuildingLevelDiff {
227  fn from(mut value: f64) -> Self {
228    value = value.round();
229    debug_assert!(value.is_finite());
230    debug_assert!(value >= f64::from(i8::MIN));
231    debug_assert!(value <= f64::from(i8::MAX));
232    Self::new(value as i8)
233  }
234}
235
236impl const PartialEq<i8> for BuildingLevelDiff {
237  fn eq(&self, other: &i8) -> bool {
238    self.0.eq(other)
239  }
240}
241
242impl const PartialOrd<i8> for BuildingLevelDiff {
243  fn partial_cmp(&self, other: &i8) -> Option<cmp::Ordering> {
244    self.0.partial_cmp(other)
245  }
246}
247
248/// Shorthand for [`BuildingLevel::new`].
249#[macro_export]
250macro_rules! lv {
251  ($level:expr) => {
252    const { $crate::infrastructure::building::level::BuildingLevel::new($level) }
253  };
254}
255
256/// Creates a building with a random level.
257#[macro_export]
258macro_rules! with_random_level {
259  ($building:ident) => {{ $crate::infrastructure::prelude::$building::with_random_level() }};
260  ($building:ident, $max:expr) => {{
261    $crate::infrastructure::prelude::$building::with_random_level_in()
262      .max($crate::lv!($max))
263      .call()
264  }};
265  ($building:ident, $min:expr, $max:expr) => {{
266    $crate::infrastructure::prelude::$building::with_random_level_in()
267      .min($crate::lv!($min))
268      .max($crate::lv!($max))
269      .call()
270  }};
271}