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