#![allow(clippy::module_name_repetitions)]
use std::time::Duration;
use chrono::{DateTime, Local};
use enum_map::{Enum, EnumMap};
use num_derive::FromPrimitive;
use strum::{EnumIter, IntoEnumIterator};
use super::{ArrSkip, CCGet, CFPGet, CSTGet, EnumMapGet, SFError, ServerTime};
#[derive(Debug, Default, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Underworld {
pub buildings: EnumMap<UnderworldBuildingType, UnderworldBuilding>,
pub units: EnumMap<UnderworldUnitType, UnderworldUnit>,
pub production: EnumMap<UnderworldResourceType, UnderworldProduction>,
pub last_collectable_update: Option<DateTime<Local>>,
pub souls_current: u64,
pub souls_limit: u64,
pub upgrade_building: Option<UnderworldBuildingType>,
pub upgrade_finish: Option<DateTime<Local>>,
pub upgrade_begin: Option<DateTime<Local>>,
pub lure_level: u16,
pub lured_today: u16,
pub lure_suggestion: Option<LureSuggestion>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LureSuggestion(pub(crate) u32);
#[derive(Debug, Default, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct UnderworldCost {
pub time: Duration,
pub silver: u64,
pub souls: u64,
}
impl UnderworldCost {
pub(crate) fn parse(data: &[i64]) -> Result<UnderworldCost, SFError> {
Ok(UnderworldCost {
time: Duration::from_secs(data.csiget(0, "u time cost", 0)?),
silver: data.csiget(1, "u silver cost", u64::MAX)?,
souls: data.csiget(2, "u sould cost", u64::MAX)?,
})
}
}
impl Underworld {
pub(crate) fn update_building_prices(
&mut self,
data: &[i64],
) -> Result<(), SFError> {
for (pos, typ) in UnderworldBuildingType::iter().enumerate() {
self.buildings.get_mut(typ).upgrade_cost = UnderworldCost::parse(
data.skip(pos * 3, "underworld building prices")?,
)?;
}
Ok(())
}
pub(crate) fn update_underworld_unit_prices(
&mut self,
data: &[i64],
) -> Result<(), SFError> {
for (pos, typ) in UnderworldUnitType::iter().enumerate() {
self.units.get_mut(typ).upgrade_next_lvl =
data.csiget(pos * 3, "uunit next lvl", 0)?;
self.units.get_mut(typ).upgrade_cost.silver =
data.csiget(1 + pos * 3, "uunit upgrade gold", 0)?;
self.units.get_mut(typ).upgrade_cost.souls =
data.csiget(2 + pos * 3, "uunit upgrade gold", 0)?;
}
Ok(())
}
pub(crate) fn update(
&mut self,
data: &[i64],
server_time: ServerTime,
) -> Result<(), SFError> {
for (pos, typ) in UnderworldBuildingType::iter().enumerate() {
self.buildings.get_mut(typ).level =
data.csiget(448 + pos, "building level", 0)?;
}
for (i, typ) in UnderworldUnitType::iter().enumerate() {
let start = 146 + i * 148;
self.units.get_mut(typ).upgraded_amount =
data.csiget(start, "uunit upgrade level", 0)?;
self.units.get_mut(typ).count =
data.csiget(start + 1, "uunit count", 0)?;
self.units.get_mut(typ).total_attributes =
data.csiget(start + 2, "uunit atr bonus", 0)?;
self.units.get_mut(typ).level =
data.csiget(start + 3, "uunit level", 0)?;
}
#[allow(clippy::enum_glob_use)]
{
use UnderworldResourceType::*;
self.production.get_mut(Souls).last_collectable =
data.csiget(459, "uu souls in building", 0)?;
self.production.get_mut(Souls).limit =
data.csiget(460, "uu sould max in building", 0)?;
self.souls_limit = data.csiget(461, "uu souls max saved", 0)?;
self.production.get_mut(Souls).per_hour =
data.csiget(463, "uu souls per hour", 0)?;
self.production.get_mut(Silver).last_collectable =
data.csiget(464, "uu gold in building", 0)?;
self.production.get_mut(Silver).limit =
data.csiget(465, "uu max gold in building", 0)?;
self.production.get_mut(Silver).per_hour =
data.csiget(466, "uu gold ", 0)?;
self.production.get_mut(ThirstForAdventure).last_collectable =
data.csiget(473, "uu alu in building", 0)?;
self.production.get_mut(ThirstForAdventure).limit =
data.csiget(474, "uu max stored alu", 0)?;
self.production.get_mut(ThirstForAdventure).per_hour =
data.csiget(475, "uu alu per day", 0)?;
}
self.last_collectable_update =
data.cstget(467, "uw resource time", server_time)?;
self.upgrade_building =
data.cfpget(468, "u building upgrade", |x| x - 1)?;
self.upgrade_finish = data.cstget(469, "u expand end", server_time)?;
self.upgrade_begin =
data.cstget(470, "u upgrade begin", server_time)?;
self.lure_level = data.csiget(471, "uu lure lvl", 0)?;
self.lured_today = data.csiget(472, "u battles today", 0)?;
Ok(())
}
}
#[derive(Debug, Clone, Copy, strum::EnumCount, Enum, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub enum UnderworldResourceType {
Souls = 0,
Silver = 1,
#[doc(alias = "ALU")]
ThirstForAdventure = 2,
}
#[derive(Debug, Default, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct UnderworldProduction {
pub last_collectable: u64,
pub limit: u64,
pub per_hour: u64,
}
#[derive(
Debug,
Clone,
Copy,
FromPrimitive,
strum::EnumCount,
Enum,
EnumIter,
PartialEq,
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub enum UnderworldBuildingType {
HeartOfDarkness = 0,
Gate = 1,
GoldPit = 2,
SoulExtractor = 3,
GoblinPit = 4,
TortureChamber = 5,
GladiatorTrainer = 6,
TrollBlock = 7,
Adventuromatic = 8,
Keeper = 9,
}
#[derive(Debug, Clone, Copy, strum::EnumCount, Enum, EnumIter, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub enum UnderworldUnitType {
Goblin = 0,
Troll = 1,
Keeper = 2,
}
#[derive(Debug, Default, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct UnderworldBuilding {
pub level: u8,
pub upgrade_cost: UnderworldCost,
}
#[derive(Debug, Default, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct UnderworldUnit {
pub level: u16,
pub count: u16,
pub total_attributes: u32,
pub upgraded_amount: u16,
pub upgrade_cost: UnderworldCost,
pub upgrade_next_lvl: u16,
}