Skip to main content

nil_core/infrastructure/
storage.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use crate::continent::Coord;
5use crate::error::{Error, Result};
6use crate::infrastructure::building::{Building, BuildingLevel, StorageId};
7use derive_more::{Deref, From, Into};
8use nil_num::growth::growth;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11use std::ops::{Add, AddAssign, Sub, SubAssign};
12
13/// A building that stores resources.
14pub trait Storage: Building {
15  fn storage_id(&self) -> StorageId;
16  /// Storage capacity at the **current** level.
17  fn capacity(&self, stats: &StorageStatsTable) -> Result<StorageCapacity>;
18  /// Storage capacity at its **minimum** level.
19  fn min_capacity(&self) -> StorageCapacity;
20  /// Storage capacity at its **maximum** level.
21  fn max_capacity(&self) -> StorageCapacity;
22}
23
24#[derive(Clone, Debug, Deserialize, Serialize)]
25#[serde(rename_all = "camelCase")]
26pub struct StorageStats {
27  pub level: BuildingLevel,
28  pub capacity: StorageCapacity,
29}
30
31#[derive(Clone, Debug, Deserialize, Serialize)]
32#[serde(rename_all = "camelCase")]
33pub struct StorageStatsTable {
34  id: StorageId,
35  table: HashMap<BuildingLevel, StorageStats>,
36}
37
38impl StorageStatsTable {
39  pub(crate) fn new(storage: &dyn Storage) -> Self {
40    let max_level = *storage.max_level();
41    let mut table = HashMap::with_capacity((max_level).into());
42
43    let mut capacity = f64::from(storage.min_capacity());
44    let capacity_growth = growth()
45      .floor(capacity)
46      .ceil(storage.max_capacity())
47      .max_level(max_level)
48      .call();
49
50    for level in 1..=max_level {
51      let level = BuildingLevel::new(level);
52      table.insert(
53        level,
54        StorageStats {
55          level,
56          capacity: StorageCapacity::from(capacity.ceil()),
57        },
58      );
59
60      debug_assert!(capacity.is_normal());
61
62      capacity += capacity * capacity_growth;
63    }
64
65    table.shrink_to_fit();
66
67    Self { id: storage.storage_id(), table }
68  }
69
70  #[inline]
71  pub fn id(&self) -> StorageId {
72    self.id
73  }
74
75  #[inline]
76  pub fn get(&self, level: BuildingLevel) -> Result<&StorageStats> {
77    self
78      .table
79      .get(&level)
80      .ok_or(Error::StorageStatsNotFoundForLevel(self.id, level))
81  }
82}
83
84/// Storage capacity of a building.
85#[derive(
86  Clone,
87  Copy,
88  Debug,
89  Deref,
90  Default,
91  From,
92  Into,
93  PartialEq,
94  Eq,
95  PartialOrd,
96  Ord,
97  Deserialize,
98  Serialize,
99)]
100#[into(u32, f64)]
101pub struct StorageCapacity(u32);
102
103impl StorageCapacity {
104  #[inline]
105  pub const fn new(value: u32) -> Self {
106    Self(value)
107  }
108}
109
110impl PartialEq<u32> for StorageCapacity {
111  fn eq(&self, other: &u32) -> bool {
112    self.0.eq(other)
113  }
114}
115
116impl Add for StorageCapacity {
117  type Output = StorageCapacity;
118
119  fn add(self, rhs: Self) -> Self::Output {
120    Self(self.0.saturating_add(rhs.0))
121  }
122}
123
124impl Add<u32> for StorageCapacity {
125  type Output = StorageCapacity;
126
127  fn add(self, rhs: u32) -> Self::Output {
128    Self(self.0.saturating_add(rhs))
129  }
130}
131
132impl AddAssign for StorageCapacity {
133  fn add_assign(&mut self, rhs: Self) {
134    *self = *self + rhs;
135  }
136}
137
138impl AddAssign<u32> for StorageCapacity {
139  fn add_assign(&mut self, rhs: u32) {
140    *self = *self + rhs;
141  }
142}
143
144impl Sub for StorageCapacity {
145  type Output = StorageCapacity;
146
147  fn sub(self, rhs: Self) -> Self::Output {
148    Self(self.0.saturating_sub(rhs.0))
149  }
150}
151
152impl Sub<u32> for StorageCapacity {
153  type Output = StorageCapacity;
154
155  fn sub(self, rhs: u32) -> Self::Output {
156    Self(self.0.saturating_sub(rhs))
157  }
158}
159
160impl SubAssign for StorageCapacity {
161  fn sub_assign(&mut self, rhs: Self) {
162    *self = *self - rhs;
163  }
164}
165
166impl SubAssign<u32> for StorageCapacity {
167  fn sub_assign(&mut self, rhs: u32) {
168    *self = *self - rhs;
169  }
170}
171
172impl From<f64> for StorageCapacity {
173  fn from(value: f64) -> Self {
174    Self::new(value as u32)
175  }
176}
177
178#[derive(Clone, Debug, Default, Deserialize, Serialize)]
179#[serde(rename_all = "camelCase")]
180pub struct OverallStorageCapacity {
181  pub silo: StorageCapacity,
182  pub warehouse: StorageCapacity,
183}
184
185impl Add for OverallStorageCapacity {
186  type Output = OverallStorageCapacity;
187
188  fn add(mut self, rhs: Self) -> Self::Output {
189    self += rhs;
190    self
191  }
192}
193
194impl AddAssign for OverallStorageCapacity {
195  fn add_assign(&mut self, rhs: Self) {
196    self.silo += rhs.silo;
197    self.warehouse += rhs.warehouse;
198  }
199}
200
201#[derive(Clone, Copy, Debug, Default, Deref, From, Into)]
202pub struct StorageCapacityWeight(f64);
203
204#[derive(Clone, Debug)]
205pub struct OverallStorageCapacityWeight {
206  pub coord: Coord,
207  pub silo: StorageCapacityWeight,
208  pub warehouse: StorageCapacityWeight,
209}
210
211impl OverallStorageCapacityWeight {
212  pub fn new(coord: Coord) -> Self {
213    Self {
214      coord,
215      silo: StorageCapacityWeight::default(),
216      warehouse: StorageCapacityWeight::default(),
217    }
218  }
219}