nil_core/infrastructure/building/prefecture/
build_queue.rs1use crate::continent::Coord;
5use crate::error::{Error, Result};
6use crate::infrastructure::building::{BuildingId, BuildingLevel, BuildingStatsTable};
7use crate::infrastructure::queue::{InfrastructureQueue, InfrastructureQueueOrder};
8use crate::resources::Resources;
9use crate::resources::workforce::Workforce;
10use nil_num::ops::MulCeil;
11use serde::{Deserialize, Serialize};
12use std::collections::VecDeque;
13use strum::EnumIs;
14use uuid::Uuid;
15
16#[derive(Clone, Debug, Default, Deserialize, Serialize)]
17#[serde(rename_all = "camelCase")]
18pub struct PrefectureBuildQueue {
19 orders: VecDeque<PrefectureBuildOrder>,
20}
21
22impl PrefectureBuildQueue {
23 pub(crate) fn build(
24 &mut self,
25 request: &PrefectureBuildOrderRequest,
26 table: &BuildingStatsTable,
27 current_level: BuildingLevel,
28 current_resources: Option<&Resources>,
29 ) -> Result<&PrefectureBuildOrder> {
30 let id = table.id();
31 let mut target_level = self.resolve_level(id, current_level);
32
33 let kind = request.kind;
34 if kind.is_demolition() && target_level <= table.min_level() {
35 return Err(Error::CannotDecreaseBuildingLevel(id));
36 } else if kind.is_construction() && target_level >= table.max_level() {
37 return Err(Error::CannotIncreaseBuildingLevel(id));
38 }
39
40 target_level += match kind {
41 PrefectureBuildOrderKind::Construction => 1i8,
42 PrefectureBuildOrderKind::Demolition => -1i8,
43 };
44
45 let resources = table.get(target_level)?.resources.clone();
46 if let PrefectureBuildOrderKind::Construction = kind
47 && let Some(current_resources) = current_resources
48 && current_resources
49 .checked_sub(&resources)
50 .is_none()
51 {
52 return Err(Error::InsufficientResources);
53 }
54
55 let mut workforce = table.get(target_level)?.workforce;
56 kind.apply_modifier(&mut workforce);
57
58 self.orders.push_back(PrefectureBuildOrder {
59 id: PrefectureBuildOrderId::new(),
60 kind,
61 building: id,
62 level: target_level,
63 resources,
64 workforce,
65 state: PrefectureBuildOrderState::new(workforce),
66 });
67
68 let len = self.orders.len();
69 Ok(unsafe {
70 self
71 .orders
72 .get(len.unchecked_sub(1))
73 .unwrap_unchecked()
74 })
75 }
76
77 #[must_use]
79 pub(crate) fn cancel(&mut self) -> Option<PrefectureBuildOrder> {
80 self.orders.pop_back()
81 }
82
83 pub fn resolve_level(&self, building: BuildingId, current_level: BuildingLevel) -> BuildingLevel {
84 self
85 .iter()
86 .filter(|order| order.building() == building)
87 .fold(current_level, |acc, order| {
88 match order.kind() {
89 PrefectureBuildOrderKind::Construction => acc + 1u8,
90 PrefectureBuildOrderKind::Demolition => acc - 1u8,
91 }
92 })
93 }
94}
95
96impl InfrastructureQueue<PrefectureBuildOrder> for PrefectureBuildQueue {
97 fn queue(&self) -> &VecDeque<PrefectureBuildOrder> {
98 &self.orders
99 }
100
101 fn queue_mut(&mut self) -> &mut VecDeque<PrefectureBuildOrder> {
102 &mut self.orders
103 }
104}
105
106#[must_use]
107#[derive(Clone, Debug, Deserialize, Serialize)]
108#[serde(rename_all = "camelCase")]
109pub struct PrefectureBuildOrder {
110 id: PrefectureBuildOrderId,
111 kind: PrefectureBuildOrderKind,
112 building: BuildingId,
113 level: BuildingLevel,
114 resources: Resources,
115 workforce: Workforce,
116 state: PrefectureBuildOrderState,
117}
118
119impl PrefectureBuildOrder {
120 #[inline]
121 pub fn id(&self) -> PrefectureBuildOrderId {
122 self.id
123 }
124
125 #[inline]
126 pub fn kind(&self) -> PrefectureBuildOrderKind {
127 self.kind
128 }
129
130 #[inline]
131 pub fn building(&self) -> BuildingId {
132 self.building
133 }
134
135 #[inline]
136 pub fn resources(&self) -> &Resources {
137 &self.resources
138 }
139}
140
141impl InfrastructureQueueOrder for PrefectureBuildOrder {
142 fn is_done(&self) -> bool {
143 self.state.is_done()
144 }
145
146 fn set_done(&mut self) {
147 self.state = PrefectureBuildOrderState::Done;
148 }
149
150 fn pending_workforce(&self) -> Option<Workforce> {
151 self.state.pending_workforce()
152 }
153
154 fn pending_workforce_mut(&mut self) -> Option<&mut Workforce> {
155 self.state.pending_workforce_mut()
156 }
157}
158
159#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
160pub struct PrefectureBuildOrderId(Uuid);
161
162impl PrefectureBuildOrderId {
163 #[must_use]
164 pub fn new() -> Self {
165 Self(Uuid::new_v4())
166 }
167}
168
169impl Default for PrefectureBuildOrderId {
170 fn default() -> Self {
171 Self::new()
172 }
173}
174
175#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, EnumIs)]
176#[serde(rename_all = "kebab-case")]
177pub enum PrefectureBuildOrderKind {
178 Construction,
179 Demolition,
180}
181
182impl PrefectureBuildOrderKind {
183 fn apply_modifier(self, workforce: &mut Workforce) {
184 if let Self::Demolition = self {
185 *workforce = workforce.mul_ceil(0.5).into();
186 }
187 }
188}
189
190#[derive(Clone, Debug, EnumIs, Deserialize, Serialize)]
191#[serde(tag = "kind", rename_all = "kebab-case")]
192pub enum PrefectureBuildOrderState {
193 Pending { workforce: Workforce },
194 Done,
195}
196
197impl PrefectureBuildOrderState {
198 fn pending_workforce(&self) -> Option<Workforce> {
199 if let Self::Pending { workforce } = self { Some(*workforce) } else { None }
200 }
201
202 fn pending_workforce_mut(&mut self) -> Option<&mut Workforce> {
203 if let Self::Pending { workforce } = self { Some(workforce) } else { None }
204 }
205}
206
207impl PrefectureBuildOrderState {
208 fn new(workforce: Workforce) -> Self {
209 Self::Pending { workforce }
210 }
211}
212
213#[derive(Clone, Debug, Deserialize, Serialize)]
214#[serde(rename_all = "camelCase")]
215pub struct PrefectureBuildOrderRequest {
216 pub coord: Coord,
217 pub building: BuildingId,
218 pub kind: PrefectureBuildOrderKind,
219}