Skip to main content

nil_core/world/resources/
mod.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4#[cfg(test)]
5mod tests;
6
7use crate::continent::index::ContinentKey;
8use crate::error::Result;
9use crate::resources::diff::ResourcesDiff;
10use crate::resources::maintenance::MaintenanceBalance;
11use crate::resources::prelude::Maintenance;
12use crate::resources::{Food, Resources};
13use crate::ruler::Ruler;
14use crate::world::World;
15use nil_num::mul_ceil::MulCeil;
16
17impl World {
18  /// Increases the resources of a ruler, ensuring their storage do not overflow.
19  pub(crate) fn add_resources_within_capacity<R>(
20    &mut self,
21    ruler: R,
22    resources: Resources,
23  ) -> Result<()>
24  where
25    R: Into<Ruler>,
26  {
27    let ruler: Ruler = ruler.into();
28    let capacity = self.get_storage_capacity(ruler.clone())?;
29    let resources_diff = ResourcesDiff::try_from(resources)?;
30
31    self
32      .ruler_mut(&ruler)?
33      .resources_mut()
34      .add_within_capacity(resources_diff, capacity);
35
36    Ok(())
37  }
38
39  pub(crate) fn get_maintenance<R>(&self, ruler: R) -> Result<Maintenance>
40  where
41    R: Into<Ruler>,
42  {
43    let ruler: Ruler = ruler.into();
44    let stats = self.stats().infrastructure();
45    let mut maintenance = self.military().maintenance_of(ruler.clone());
46
47    for city in self.continent().cities_of(ruler) {
48      maintenance += city.maintenance(&stats)?;
49    }
50
51    Ok(maintenance)
52  }
53
54  pub(crate) fn get_maintenance_balance<R>(&self, ruler: R) -> Result<MaintenanceBalance>
55  where
56    R: Into<Ruler>,
57  {
58    let ruler: Ruler = ruler.into();
59    let stats = self.stats().infrastructure();
60
61    let mut production = Food::new(0);
62    let mut maintenance = self.military().maintenance_of(ruler.clone());
63
64    for city in self.continent().cities_of(ruler) {
65      maintenance += city.maintenance(&stats)?;
66      production += city.round_production(&stats)?.food;
67    }
68
69    Ok(MaintenanceBalance { maintenance, production })
70  }
71
72  pub fn get_weighted_resources<K>(&self, key: K) -> Result<Resources>
73  where
74    K: ContinentKey,
75  {
76    let city = key
77      .into_coord(self.continent.size())
78      .and_then(|coord| self.city(coord))?;
79
80    let capacity_weight = self.get_storage_capacity_weight(city.coord())?;
81    let mut resources = self.ruler(city.owner())?.resources();
82
83    macro_rules! apply {
84      ($res:ident, $storage:ident) => {
85        let weight = f64::from(capacity_weight.$storage);
86        resources.$res = resources.$res.mul_ceil(weight).into();
87      };
88    }
89
90    apply!(food, silo);
91    apply!(iron, warehouse);
92    apply!(stone, warehouse);
93    apply!(wood, warehouse);
94
95    Ok(resources)
96  }
97
98  /// Withdraws up to the requested resources, storing the amount withdrawn in `resources`.
99  pub(crate) fn withdraw_resources_up_to<R>(
100    &mut self,
101    ruler: R,
102    resources: &mut Resources,
103  ) -> Result<()>
104  where
105    R: Into<Ruler>,
106  {
107    let mut ruler = self.ruler_mut(&ruler.into())?;
108    let current_resources = ruler.take_resources();
109    if let Some(result) = current_resources.checked_sub(*resources) {
110      *ruler.resources_mut() = result;
111    } else {
112      *resources = current_resources;
113    }
114
115    Ok(())
116  }
117}