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  /// How many cities can be controlled with this amount of influence.
44  #[inline]
45  pub fn city_limit(&self) -> u32 {
46    nearest_triangle(self.0.get())
47  }
48}
49
50const impl Default for Influence {
51  fn default() -> Self {
52    Self::MIN
53  }
54}
55
56check_total_resource_ratio!(
57  Influence::FOOD_RATIO,
58  Influence::IRON_RATIO,
59  Influence::STONE_RATIO,
60  Influence::WOOD_RATIO
61);
62
63/// Resources required to acquire one unit of influence.
64#[derive(Copy, Debug, Deserialize, Serialize, ConstDeref)]
65#[derive_const(Clone, PartialEq, Eq)]
66#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
67pub struct InfluenceResourceCost(Resources);
68
69impl InfluenceResourceCost {
70  pub const fn new() -> Self {
71    Self(Resources {
72      food: Food::from((Influence::COST * Influence::FOOD_RATIO).round()),
73      iron: Iron::from((Influence::COST * Influence::IRON_RATIO).round()),
74      stone: Stone::from((Influence::COST * Influence::STONE_RATIO).round()),
75      wood: Wood::from((Influence::COST * Influence::WOOD_RATIO).round()),
76    })
77  }
78}
79
80const impl Default for InfluenceResourceCost {
81  fn default() -> Self {
82    Self::new()
83  }
84}