nil_core/world/round/
mod.rs1mod behavior;
5mod maneuver;
6
7#[cfg(test)]
8mod tests;
9
10use crate::error::Result;
11use crate::player::{Player, PlayerId};
12use crate::resources::prelude::*;
13use crate::round::Round;
14use crate::ruler::Ruler;
15use crate::world::World;
16use std::collections::HashMap;
17
18impl World {
19 #[inline]
20 pub fn round(&self) -> &Round {
21 &self.round
22 }
23
24 pub fn start_round(&mut self) -> Result<()> {
25 let ids = self
26 .player_manager
27 .active_players()
28 .map(Player::id);
29
30 self.round.start(ids)?;
31 self.emit_round()?;
32
33 Ok(())
34 }
35
36 pub fn set_player_ready(&mut self, player: &PlayerId, is_ready: bool) -> Result<()> {
37 self.round.set_ready(player, is_ready);
38
39 if self.round.is_done() {
40 self.next_round(true)?;
41 } else {
42 self.emit_round()?;
43 }
44
45 Ok(())
46 }
47
48 pub fn dangerously_end_round(&mut self, emit: bool) -> Result<()> {
50 self.round.dangerously_set_done();
51 self.next_round(emit)?;
52 Ok(())
53 }
54
55 pub(super) fn next_round(&mut self, emit: bool) -> Result<()> {
56 let ids = self
57 .player_manager
58 .active_players()
59 .map(Player::id);
60
61 self.round.next(ids)?;
62 self.prepare_next_round()?;
63 self.consume_pending_save()?;
64
65 if emit {
66 self.emit_round()?;
67 }
68
69 if let Some(on_next_round) = self.on_next_round.clone() {
70 on_next_round.call(self);
71 }
72
73 Ok(())
74 }
75
76 fn prepare_next_round(&mut self) -> Result<()> {
77 self.update_resources()?;
78 self.process_city_queues();
79 self.collapse_armies();
80 self.process_maneuvers()?;
81 self.update_ranking()?;
82 self.process_npc_behavior()?;
83 Ok(())
84 }
85
86 fn update_resources(&mut self) -> Result<()> {
89 let stats = self.stats.infrastructure.as_ref();
90 let mut diff: HashMap<Ruler, ResourcesDiff> = HashMap::new();
91
92 for city in self.continent.cities() {
93 let owner = city.owner().clone();
94 let resources = diff.entry(owner).or_default();
95 *resources += city.round_production(stats)?;
96 resources.food -= city.maintenance(stats)?;
97 }
98
99 for (ruler, mut resources) in diff {
100 resources.food -= self.military.maintenance_of(ruler.clone());
101 let capacity = self.get_storage_capacity(ruler.clone())?;
102 self
103 .ruler_mut(&ruler)?
104 .resources_mut()
105 .add_within_capacity(&resources, &capacity);
106 }
107
108 Ok(())
109 }
110
111 fn process_city_queues(&mut self) {
113 let config = self.config();
114 for city in self.continent.cities_mut() {
115 let coord = city.coord();
116 let owner = city.owner().clone();
117 let infrastructure = city.infrastructure_mut();
118
119 infrastructure.process_prefecture_build_queue(&config);
120
121 macro_rules! process_recruit_queue {
122 ($building:ident) => {
123 paste::paste! {
124 if let Some(personnel) = infrastructure.[<process_ $building:snake _recruit_queue>](&config) {
125 self.military.spawn(coord, owner.clone(), personnel);
126 }
127 }
128 };
129 }
130
131 process_recruit_queue!(Academy);
132 process_recruit_queue!(Stable);
133 process_recruit_queue!(Workshop);
134 }
135 }
136}