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