pub mod stability;
use crate::city::stability::Stability;
use crate::continent::Coord;
use crate::error::Result;
use crate::infrastructure::Infrastructure;
use crate::infrastructure::building::StorageId;
use crate::infrastructure::stats::InfrastructureStats;
use crate::infrastructure::storage::OverallStorageCapacity;
use crate::npc::bot::BotId;
use crate::npc::precursor::PrecursorId;
use crate::player::PlayerId;
use crate::ranking::score::Score;
use crate::resources::Resources;
use crate::resources::maintenance::Maintenance;
use crate::ruler::Ruler;
use bon::Builder;
use derive_more::{Deref, DerefMut, From};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct City {
#[builder(start_fn, into)]
coord: Coord,
#[builder(into)]
name: CityName,
#[builder(into)]
owner: Ruler,
#[builder(default)]
infrastructure: Infrastructure,
#[builder(default)]
stability: Stability,
}
impl City {
#[inline]
pub fn coord(&self) -> Coord {
self.coord
}
#[inline]
pub fn name(&self) -> &CityName {
&self.name
}
pub(crate) fn name_mut(&mut self) -> &mut CityName {
&mut self.name
}
#[inline]
pub fn owner(&self) -> &Ruler {
&self.owner
}
#[inline]
pub fn infrastructure(&self) -> &Infrastructure {
&self.infrastructure
}
#[inline]
pub fn infrastructure_mut(&mut self) -> &mut Infrastructure {
&mut self.infrastructure
}
#[inline]
pub fn stability(&self) -> Stability {
self.stability
}
pub(crate) fn stability_mut(&mut self) -> &mut Stability {
&mut self.stability
}
#[inline]
pub fn player(&self) -> Option<PlayerId> {
self.owner().player().cloned()
}
#[inline]
pub fn is_owned_by_player(&self) -> bool {
self.owner.player().is_some()
}
pub fn is_owned_by_player_and<F>(&self, f: F) -> bool
where
F: FnOnce(&PlayerId) -> bool,
{
self.owner.player().is_some_and(f)
}
#[inline]
pub fn is_owned_by_bot(&self) -> bool {
self.owner.bot().is_some()
}
pub fn is_owned_by_bot_and<F>(&self, f: F) -> bool
where
F: FnOnce(&BotId) -> bool,
{
self.owner.bot().is_some_and(f)
}
#[inline]
pub fn is_owned_by_precursor(&self) -> bool {
self.owner.precursor().is_some()
}
pub fn is_owned_by_precursor_and<F>(&self, f: F) -> bool
where
F: FnOnce(PrecursorId) -> bool,
{
self.owner.precursor().is_some_and(f)
}
#[inline]
pub fn score(&self, stats: &InfrastructureStats) -> Result<Score> {
self.infrastructure.score(stats)
}
pub fn round_production(&self, stats: &InfrastructureStats) -> Result<Resources> {
let mut resources = self
.infrastructure
.round_base_production(stats)?;
resources.food *= self.stability;
resources.iron *= self.stability;
resources.stone *= self.stability;
resources.wood *= self.stability;
Ok(resources)
}
pub fn maintenance(&self, stats: &InfrastructureStats) -> Result<Maintenance> {
self.infrastructure.base_maintenance(stats)
}
pub fn storage_capacity(&self, stats: &InfrastructureStats) -> Result<OverallStorageCapacity> {
let silo_stats = stats.storage(StorageId::Silo)?;
let warehouse_stats = stats.storage(StorageId::Warehouse)?;
Ok(OverallStorageCapacity {
silo: self
.infrastructure
.storage(StorageId::Silo)
.capacity(silo_stats)?,
warehouse: self
.infrastructure
.storage(StorageId::Warehouse)
.capacity(warehouse_stats)?,
})
}
}
impl From<&City> for Ruler {
fn from(city: &City) -> Self {
city.owner.clone()
}
}
#[derive(Clone, Debug, Deref, DerefMut, From, Deserialize, Serialize)]
#[from(String, &str)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct CityName(String);
impl CityName {
pub fn new(name: impl AsRef<str>) -> Self {
Self(name.as_ref().to_owned())
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct PublicCity {
coord: Coord,
name: Arc<str>,
owner: Ruler,
}
impl From<&City> for PublicCity {
fn from(city: &City) -> Self {
Self {
coord: city.coord,
name: Arc::from(city.name.as_str()),
owner: city.owner.clone(),
}
}
}
#[derive(Builder, Clone, Debug, Default, Deserialize, Serialize)]
#[serde(default, rename_all = "camelCase")]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
#[cfg_attr(feature = "typescript", ts(optional_fields))]
pub struct CitySearch {
#[builder(default, with = FromIterator::from_iter)]
#[cfg_attr(feature = "typescript", ts(as = "Option<Vec<Coord>>"))]
pub coord: Vec<Coord>,
#[builder(default, with = FromIterator::from_iter)]
#[cfg_attr(feature = "typescript", ts(as = "Option<Vec<CityName>>"))]
pub name: Vec<CityName>,
}
impl From<Coord> for CitySearch {
fn from(coord: Coord) -> Self {
Self::from_iter([coord])
}
}
impl From<CityName> for CitySearch {
fn from(name: CityName) -> Self {
Self::from_iter([name])
}
}
impl FromIterator<Coord> for CitySearch {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = Coord>,
{
Self::builder().coord(iter).build()
}
}
impl FromIterator<CityName> for CitySearch {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = CityName>,
{
Self::builder().name(iter).build()
}
}