Skip to main content

nil_core/infrastructure/building/stable/
mod.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4pub mod recruit_catalog;
5pub mod recruit_queue;
6
7use crate::check_total_resource_ratio;
8use crate::infrastructure::building::{BuildingId, BuildingLevel};
9use crate::infrastructure::queue::InfrastructureQueue;
10use crate::infrastructure::requirements::InfrastructureRequirements;
11use crate::ranking::score::Score;
12use crate::resources::cost::{Cost, ResourceRatio};
13use crate::resources::maintenance::MaintenanceRatio;
14use crate::resources::workforce::{Workforce, WorkforceSource};
15use crate::world::config::WorldConfig;
16use nil_core_macros::Building;
17use recruit_queue::{StableRecruitOrder, StableRecruitQueue};
18use serde::{Deserialize, Serialize};
19
20#[derive(Building, Clone, Debug, Deserialize, Serialize)]
21#[serde(rename_all = "camelCase")]
22pub struct Stable {
23  level: BuildingLevel,
24  enabled: bool,
25  recruit_queue: StableRecruitQueue,
26}
27
28impl Stable {
29  pub const ID: BuildingId = BuildingId::Stable;
30
31  pub const MIN_LEVEL: BuildingLevel = BuildingLevel::ZERO;
32  pub const MAX_LEVEL: BuildingLevel = BuildingLevel::new(20);
33
34  pub const MIN_COST: Cost = Cost::new(1_500);
35  pub const MAX_COST: Cost = Cost::new(50_000);
36
37  pub const WOOD_RATIO: ResourceRatio = ResourceRatio::new(0.4);
38  pub const STONE_RATIO: ResourceRatio = ResourceRatio::new(0.3);
39  pub const IRON_RATIO: ResourceRatio = ResourceRatio::new(0.3);
40  pub const MAINTENANCE_RATIO: MaintenanceRatio = MaintenanceRatio::new(0.005);
41
42  pub const MIN_WORKFORCE: Workforce = Workforce::new(1);
43  pub const MAX_WORKFORCE: Workforce = Workforce::new(150);
44
45  pub const MIN_SCORE: Score = Score::new(20);
46  pub const MAX_SCORE: Score = Score::new(639);
47
48  pub const INFRASTRUCTURE_REQUIREMENTS: InfrastructureRequirements =
49    InfrastructureRequirements::builder()
50      .prefecture(BuildingLevel::new(3))
51      .academy(BuildingLevel::new(1))
52      .build();
53
54  pub fn recruit_queue(&self) -> &StableRecruitQueue {
55    &self.recruit_queue
56  }
57
58  pub(crate) fn recruit_queue_mut(&mut self) -> &mut StableRecruitQueue {
59    &mut self.recruit_queue
60  }
61
62  #[must_use]
63  pub(crate) fn process_queue(&mut self, config: &WorldConfig) -> Option<Vec<StableRecruitOrder>> {
64    if self.enabled {
65      let workforce = self.workforce(config);
66      let orders = self.recruit_queue.process(workforce);
67      (!orders.is_empty()).then_some(orders)
68    } else {
69      None
70    }
71  }
72
73  pub(crate) fn turns_in_recruit_queue(&self, config: &WorldConfig) -> Option<f64> {
74    if self.level > 0u8 {
75      let turn = self.workforce(config);
76      let in_queue = self.recruit_queue.sum_pending_workforce();
77      Some(f64::from(in_queue) / f64::from(turn))
78    } else {
79      None
80    }
81  }
82}
83
84impl WorkforceSource for Stable {}
85
86impl Default for Stable {
87  fn default() -> Self {
88    Self {
89      level: BuildingLevel::ZERO,
90      enabled: true,
91      recruit_queue: StableRecruitQueue::default(),
92    }
93  }
94}
95
96check_total_resource_ratio!(Stable::WOOD_RATIO, Stable::STONE_RATIO, Stable::IRON_RATIO);