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