nil-core 0.8.4

Multiplayer strategy game
Documentation
// Copyright (C) Call of Nil contributors
// SPDX-License-Identifier: AGPL-3.0-only

use super::cost::{Cost, ResourceRatio};
use super::{Food, Iron, Resources, Stone, Wood};
use crate::check_total_resource_ratio;
use derive_more::Display;
use nil_num::triangle::nearest_triangle;
use nil_util::ConstDeref;
use serde::{Deserialize, Serialize};
use std::num::NonZeroU32;

/// Influência é um recurso especial que representa o poder político de um soberano
/// e é usado para determinar quantas cidades ele pode controlar simultaneamente.
///
/// A quantidade de influência necessária para controlar um número `n` de cidades é dada pela
/// fórmula `n * (n + 1) / 2`, ou seja, cresce como um número triangular.
#[derive(Copy, Debug, Display, Deserialize, Serialize, ConstDeref)]
#[derive_const(Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct Influence(NonZeroU32);

impl Influence {
  pub const MIN: Influence = Influence(NonZeroU32::MIN);
  pub const MAX: Influence = Influence(NonZeroU32::MAX);

  pub const COST: Cost = Cost::new(100_000);

  pub const FOOD_RATIO: ResourceRatio = ResourceRatio::new(0.19);
  pub const IRON_RATIO: ResourceRatio = ResourceRatio::new(0.27);
  pub const STONE_RATIO: ResourceRatio = ResourceRatio::new(0.27);
  pub const WOOD_RATIO: ResourceRatio = ResourceRatio::new(0.27);
}

impl Influence {
  /// # Safety
  ///
  /// O valor não pode ser zero.
  pub const unsafe fn new_unchecked(value: u32) -> Self {
    unsafe { Self(NonZeroU32::new_unchecked(value)) }
  }

  /// Quantas cidades podem ser controladas com esta quantidade de influência.
  #[inline]
  pub fn city_limit(&self) -> u32 {
    nearest_triangle(self.0.get())
  }
}

const impl Default for Influence {
  fn default() -> Self {
    Self::MIN
  }
}

check_total_resource_ratio!(
  Influence::FOOD_RATIO,
  Influence::IRON_RATIO,
  Influence::STONE_RATIO,
  Influence::WOOD_RATIO
);

/// Recursos necessários para adquirir uma unidade de influência.
#[derive(Copy, Debug, Deserialize, Serialize, ConstDeref)]
#[derive_const(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct InfluenceResourceCost(Resources);

impl InfluenceResourceCost {
  pub const fn new() -> Self {
    Self(Resources {
      food: Food::from((Influence::COST * Influence::FOOD_RATIO).round()),
      iron: Iron::from((Influence::COST * Influence::IRON_RATIO).round()),
      stone: Stone::from((Influence::COST * Influence::STONE_RATIO).round()),
      wood: Wood::from((Influence::COST * Influence::WOOD_RATIO).round()),
    })
  }
}

const impl Default for InfluenceResourceCost {
  fn default() -> Self {
    Self::new()
  }
}