nil_core/infrastructure/
mine.rs1use crate::error::{Error, Result};
5use crate::infrastructure::building::level::BuildingLevel;
6use crate::infrastructure::building::{Building, MineId};
7use crate::world::config::WorldConfig;
8use derive_more::Into;
9use nil_num::growth::growth;
10use nil_util::{ConstDeref, F64Math};
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13
14pub trait Mine: Building {
15 fn mine_id(&self) -> MineId;
16
17 fn production(&self, stats: &MineStatsTable) -> Result<MineProduction>;
19 fn min_production(&self) -> MineProduction;
21 fn max_production(&self) -> MineProduction;
23}
24
25#[derive(Clone, Debug, Deserialize, Serialize)]
26#[serde(rename_all = "camelCase")]
27#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
28pub struct MineStats {
29 pub level: BuildingLevel,
30 pub production: MineProduction,
31}
32
33#[derive(Clone, Debug, Deserialize, Serialize)]
34#[serde(rename_all = "camelCase")]
35#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
36pub struct MineStatsTable {
37 id: MineId,
38 table: HashMap<BuildingLevel, MineStats>,
39}
40
41impl MineStatsTable {
42 pub(crate) fn new(config: &WorldConfig, mine: &dyn Mine) -> Self {
43 let max_level = *mine.max_level();
44 let mut table = HashMap::with_capacity((max_level).into());
45
46 let speed = f64::from(config.speed());
47 let mut production = mine.min_production() * speed;
48
49 let production_growth = growth()
50 .floor(production)
51 .ceil(mine.max_production() * speed)
52 .max_level(max_level)
53 .call();
54
55 for level in 1..=max_level {
56 let level = BuildingLevel::new(level);
57 table.insert(
58 level,
59 MineStats {
60 level,
61 production: MineProduction::from(production.round()),
62 },
63 );
64
65 debug_assert!(production.is_normal());
66
67 production += production * production_growth;
68 }
69
70 table.shrink_to_fit();
71
72 Self { id: mine.mine_id(), table }
73 }
74
75 #[inline]
76 pub fn id(&self) -> MineId {
77 self.id
78 }
79
80 #[inline]
81 pub fn get(&self, level: BuildingLevel) -> Result<&MineStats> {
82 self
83 .table
84 .get(&level)
85 .ok_or(Error::MineStatsNotFoundForLevel(self.id, level))
86 }
87}
88
89#[derive(Copy, Debug, Into, Deserialize, Serialize, ConstDeref, F64Math)]
91#[derive_const(Clone, PartialEq, Eq, PartialOrd, Ord)]
92#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
93pub struct MineProduction(u32);
94
95impl MineProduction {
96 #[inline]
97 pub const fn new(value: u32) -> Self {
98 Self(value)
99 }
100}
101
102impl const From<f64> for MineProduction {
103 fn from(value: f64) -> Self {
104 Self::new(value as u32)
105 }
106}
107
108impl const From<MineProduction> for f64 {
109 fn from(value: MineProduction) -> Self {
110 f64::from(value.0)
111 }
112}