Skip to main content

nil_core/infrastructure/
mine.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use crate::error::{Error, Result};
5use crate::infrastructure::building::{Building, BuildingLevel, MineId};
6use derive_more::{Deref, Into};
7use nil_num::growth::growth;
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10
11pub trait Mine: Building {
12  fn mine_id(&self) -> MineId;
13
14  /// Amount of resources generated by the mine at its **current** level.
15  fn production(&self, stats: &MineStatsTable) -> Result<MineProduction>;
16  /// Amount of resources generated by the mine at its **minimum** level.
17  fn min_production(&self) -> MineProduction;
18  /// Amount of resources generated by the mine at its **maximum** level.
19  fn max_production(&self) -> MineProduction;
20}
21
22#[derive(Clone, Debug, Deserialize, Serialize)]
23#[serde(rename_all = "camelCase")]
24pub struct MineStats {
25  pub level: BuildingLevel,
26  pub production: MineProduction,
27}
28
29#[derive(Clone, Debug, Deserialize, Serialize)]
30#[serde(rename_all = "camelCase")]
31pub struct MineStatsTable {
32  id: MineId,
33  table: HashMap<BuildingLevel, MineStats>,
34}
35
36impl MineStatsTable {
37  pub(crate) fn new(mine: &dyn Mine) -> Self {
38    let max_level = *mine.max_level();
39    let mut table = HashMap::with_capacity((max_level).into());
40
41    let mut production = f64::from(mine.min_production());
42    let production_growth = growth()
43      .floor(production)
44      .ceil(mine.max_production())
45      .max_level(max_level)
46      .call();
47
48    for level in 1..=max_level {
49      let level = BuildingLevel::new(level);
50      table.insert(
51        level,
52        MineStats {
53          level,
54          production: MineProduction::from(production.round()),
55        },
56      );
57
58      debug_assert!(production.is_normal());
59
60      production += production * production_growth;
61    }
62
63    table.shrink_to_fit();
64
65    Self { id: mine.mine_id(), table }
66  }
67
68  #[inline]
69  pub fn id(&self) -> MineId {
70    self.id
71  }
72
73  #[inline]
74  pub fn get(&self, level: BuildingLevel) -> Result<&MineStats> {
75    self
76      .table
77      .get(&level)
78      .ok_or(Error::MineStatsNotFoundForLevel(self.id, level))
79  }
80}
81
82/// Amount of resources generated by a mine in a single round.
83#[derive(Clone, Copy, Debug, Deref, Into, Deserialize, Serialize)]
84#[into(u32, f64)]
85pub struct MineProduction(u32);
86
87impl MineProduction {
88  #[inline]
89  pub const fn new(value: u32) -> Self {
90    Self(value)
91  }
92}
93
94impl From<f64> for MineProduction {
95  fn from(value: f64) -> Self {
96    Self::new(value as u32)
97  }
98}