nil_core/infrastructure/
mine.rs1use 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 fn production(&self, stats: &MineStatsTable) -> Result<MineProduction>;
17 fn min_production(&self) -> MineProduction;
19 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#[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}