Skip to main content

nil_core/resources/
influence.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use super::cost::{Cost, ResourceRatio};
5use super::{Food, Iron, Resources, Stone, Wood};
6use crate::check_total_resource_ratio;
7use derive_more::Display;
8use nil_num::triangle::nearest_triangle;
9use nil_util::ConstDeref;
10use serde::{Deserialize, Serialize};
11use std::num::NonZeroU32;
12
13/// Influence is a special resource which represents the political power of a ruler
14/// and is used to determine how many cities they can simultaneously control.
15///
16/// The amount of influence needed to control a number `n` of cities is given by
17/// the formula `n * (n + 1) / 2`, meaning it increases as a triangular number.
18#[derive(Copy, Debug, Display, Deserialize, Serialize, ConstDeref)]
19#[derive_const(Clone, PartialEq, Eq, PartialOrd, Ord)]
20#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
21pub struct Influence(NonZeroU32);
22
23impl Influence {
24  pub const MIN: Influence = Influence(NonZeroU32::MIN);
25  pub const MAX: Influence = Influence(NonZeroU32::MAX);
26
27  pub const COST: Cost = Cost::new(100_000);
28
29  pub const FOOD_RATIO: ResourceRatio = ResourceRatio::new(0.19);
30  pub const IRON_RATIO: ResourceRatio = ResourceRatio::new(0.27);
31  pub const STONE_RATIO: ResourceRatio = ResourceRatio::new(0.27);
32  pub const WOOD_RATIO: ResourceRatio = ResourceRatio::new(0.27);
33}
34
35impl Influence {
36  /// # Safety
37  ///
38  /// Value must not be zero.
39  pub const unsafe fn new_unchecked(value: u32) -> Self {
40    unsafe { Self(NonZeroU32::new_unchecked(value)) }
41  }
42
43  /// Resources required to acquire one unit of influence.
44  pub const fn resources() -> Resources {
45    Resources {
46      food: Food::from((Self::COST * Self::FOOD_RATIO).round()),
47      iron: Iron::from((Self::COST * Self::IRON_RATIO).round()),
48      stone: Stone::from((Self::COST * Self::STONE_RATIO).round()),
49      wood: Wood::from((Self::COST * Self::WOOD_RATIO).round()),
50    }
51  }
52
53  #[inline]
54  pub fn city_limit(&self) -> u32 {
55    nearest_triangle(self.0.get())
56  }
57}
58
59impl const Default for Influence {
60  fn default() -> Self {
61    Self::MIN
62  }
63}
64
65check_total_resource_ratio!(
66  Influence::FOOD_RATIO,
67  Influence::IRON_RATIO,
68  Influence::STONE_RATIO,
69  Influence::WOOD_RATIO
70);