1#![allow(clippy::module_name_repetitions)]
2use std::time::Duration;
3
4use chrono::{DateTime, Local};
5use enum_map::{Enum, EnumMap};
6use num_derive::FromPrimitive;
7use strum::{EnumIter, IntoEnumIterator};
8
9use super::{ArrSkip, CCGet, CFPGet, CSTGet, EnumMapGet, SFError, ServerTime};
10
11#[derive(Debug, Default, Clone)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct Underworld {
15 pub buildings: EnumMap<UnderworldBuildingType, UnderworldBuilding>,
18 pub units: EnumMap<UnderworldUnitType, UnderworldUnit>,
20 pub production: EnumMap<UnderworldResourceType, UnderworldProduction>,
22 pub last_collectable_update: Option<DateTime<Local>>,
26
27 pub souls_current: u64,
31 pub souls_limit: u64,
35
36 pub upgrade_building: Option<UnderworldBuildingType>,
38 pub upgrade_finish: Option<DateTime<Local>>,
40 pub upgrade_begin: Option<DateTime<Local>>,
42
43 pub honor: u16,
46 pub lured_today: u16,
48}
49
50#[derive(Debug, Default, Clone, Copy)]
51#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
52pub struct UnderworldCost {
55 pub time: Duration,
57 pub silver: u64,
59 pub souls: u64,
61}
62
63impl UnderworldCost {
64 pub(crate) fn parse(data: &[i64]) -> Result<UnderworldCost, SFError> {
65 Ok(UnderworldCost {
66 time: Duration::from_secs(data.csiget(0, "u time cost", 0)?),
67 silver: data.csiget(1, "u silver cost", u64::MAX)?,
69 souls: data.csiget(2, "u sould cost", u64::MAX)?,
70 })
71 }
72}
73
74impl Underworld {
75 pub(crate) fn update_building_prices(
76 &mut self,
77 data: &[i64],
78 ) -> Result<(), SFError> {
79 for (pos, typ) in UnderworldBuildingType::iter().enumerate() {
80 self.buildings.get_mut(typ).upgrade_cost = UnderworldCost::parse(
81 data.skip(pos * 3, "underworld building prices")?,
82 )?;
83 }
84 Ok(())
85 }
86
87 pub(crate) fn update_underworld_unit_prices(
88 &mut self,
89 data: &[i64],
90 ) -> Result<(), SFError> {
91 for (pos, typ) in UnderworldUnitType::iter().enumerate() {
92 self.units.get_mut(typ).upgrade_next_lvl =
93 data.csiget(pos * 3, "uunit next lvl", 0)?;
94 self.units.get_mut(typ).upgrade_cost.silver =
95 data.csiget(1 + pos * 3, "uunit upgrade gold", 0)?;
96 self.units.get_mut(typ).upgrade_cost.souls =
97 data.csiget(2 + pos * 3, "uunit upgrade gold", 0)?;
98 }
99 Ok(())
100 }
101
102 pub(crate) fn update(
103 &mut self,
104 data: &[i64],
105 server_time: ServerTime,
106 ) -> Result<(), SFError> {
107 for (pos, typ) in UnderworldBuildingType::iter().enumerate() {
108 self.buildings.get_mut(typ).level =
109 data.csiget(448 + pos, "building level", 0)?;
110 }
111
112 for (i, typ) in UnderworldUnitType::iter().enumerate() {
113 let start = 146 + i * 148;
114 self.units.get_mut(typ).upgraded_amount =
115 data.csiget(start, "uunit upgrade level", 0)?;
116 self.units.get_mut(typ).count =
117 data.csiget(start + 1, "uunit count", 0)?;
118 self.units.get_mut(typ).total_attributes =
119 data.csiget(start + 2, "uunit atr bonus", 0)?;
120 self.units.get_mut(typ).level =
121 data.csiget(start + 3, "uunit level", 0)?;
122 }
123
124 #[allow(clippy::enum_glob_use)]
125 {
126 use UnderworldResourceType::*;
127 self.production.get_mut(Souls).last_collectable =
128 data.csiget(459, "uu souls in building", 0)?;
129 self.production.get_mut(Souls).limit =
130 data.csiget(460, "uu sould max in building", 0)?;
131 self.souls_limit = data.csiget(461, "uu souls max saved", 0)?;
132 self.production.get_mut(Souls).per_hour =
133 data.csiget(463, "uu souls per hour", 0)?;
134
135 self.production.get_mut(Silver).last_collectable =
136 data.csiget(464, "uu gold in building", 0)?;
137 self.production.get_mut(Silver).limit =
138 data.csiget(465, "uu max gold in building", 0)?;
139 self.production.get_mut(Silver).per_hour =
140 data.csiget(466, "uu gold ", 0)?;
141
142 self.production.get_mut(ThirstForAdventure).last_collectable =
143 data.csiget(473, "uu alu in building", 0)?;
144 self.production.get_mut(ThirstForAdventure).limit =
145 data.csiget(474, "uu max stored alu", 0)?;
146 self.production.get_mut(ThirstForAdventure).per_hour =
147 data.csiget(475, "uu alu per day", 0)?;
148 }
149
150 self.last_collectable_update =
151 data.cstget(467, "uw resource time", server_time)?;
152 self.upgrade_building =
153 data.cfpget(468, "u building upgrade", |x| x - 1)?;
154 self.upgrade_finish = data.cstget(469, "u expand end", server_time)?;
155 self.upgrade_begin =
156 data.cstget(470, "u upgrade begin", server_time)?;
157 self.honor = data.csiget(471, "uu honor", 0)?;
158 self.lured_today = data.csiget(472, "u battles today", 0)?;
159 Ok(())
160 }
161}
162
163#[derive(Debug, Clone, Copy, strum::EnumCount, Enum, PartialEq)]
164#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
165#[allow(missing_docs)]
166pub enum UnderworldResourceType {
168 Souls = 0,
169 Silver = 1,
170 #[doc(alias = "ALU")]
171 ThirstForAdventure = 2,
172}
173
174#[derive(Debug, Default, Clone)]
175#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
176pub struct UnderworldProduction {
179 pub last_collectable: u64,
184 pub limit: u64,
187 pub per_hour: u64,
190}
191
192#[derive(
193 Debug,
194 Clone,
195 Copy,
196 FromPrimitive,
197 strum::EnumCount,
198 Enum,
199 EnumIter,
200 PartialEq,
201)]
202#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
203#[allow(missing_docs)]
204pub enum UnderworldBuildingType {
206 HeartOfDarkness = 0,
207 Gate = 1,
208 GoldPit = 2,
209 SoulExtractor = 3,
210 GoblinPit = 4,
211 TortureChamber = 5,
212 GladiatorTrainer = 6,
213 TrollBlock = 7,
214 Adventuromatic = 8,
215 Keeper = 9,
216}
217
218#[derive(Debug, Clone, Copy, strum::EnumCount, Enum, EnumIter, PartialEq)]
219#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
220#[allow(missing_docs)]
221pub enum UnderworldUnitType {
223 Goblin = 0,
224 Troll = 1,
225 Keeper = 2,
226}
227
228#[derive(Debug, Default, Clone, Copy)]
229#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
230pub struct UnderworldBuilding {
232 pub level: u8,
235 pub upgrade_cost: UnderworldCost,
237}
238
239#[derive(Debug, Default, Clone)]
240#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
241pub struct UnderworldUnit {
243 pub level: u16,
245 pub count: u16,
247 pub total_attributes: u32,
249
250 pub upgraded_amount: u16,
252
253 pub upgrade_cost: UnderworldCost,
255 pub upgrade_next_lvl: u16,
257}