Skip to main content

galactic_war/
config.rs

1use indexmap::IndexMap;
2/// Contains all the config structs
3///
4/// This is everything used externally to configure the galaxy
5use serde::Deserialize;
6use std::collections::HashMap;
7
8use crate::Cost;
9
10/// Configuration for the Galaxy
11#[derive(Debug, Deserialize, Default)]
12pub struct GalaxyConfig {
13    /// Static System Count
14    pub system_count: usize,
15
16    /// Galaxy size
17    pub size: GalaxySize,
18
19    /// System Config
20    pub systems: SystemConfig,
21}
22
23#[derive(Debug, Deserialize, Default)]
24pub struct GalaxySize {
25    pub x: usize,
26    pub y: usize,
27}
28
29/// Configuration for the creation of an system
30#[derive(Debug, Default, Deserialize)]
31pub struct SystemConfig {
32    /// List of structures that will be built on the system
33    pub structures: IndexMap<String, StructureConfig>,
34
35    /// Starting resources for the system
36    pub resources: HashMap<String, usize>,
37}
38
39/// Production Configuration.
40///
41/// These are all in production per hour (3600 ticks).
42#[derive(Clone, Debug, Default, Deserialize)]
43pub struct ProductionConfig {
44    pub metal: Option<usize>,
45    pub crew: Option<usize>,
46    pub water: Option<usize>,
47}
48
49/// Storage Configuration.
50///
51/// Stores resource limit for storage.
52pub type StorageConfig = ProductionConfig;
53
54#[derive(Debug, Default, Deserialize)]
55pub struct StructureConfig {
56    /// Description of the structure.
57    pub description: Option<String>,
58
59    /// Starting level for this type of structure
60    /// If not provided it is 0
61    pub starting_level: Option<usize>,
62
63    /// Used to specify how many of each resource is produced
64    ///
65    /// The number of ticks needed to produce the resource at a level
66    pub production: Option<Vec<ProductionConfig>>,
67
68    /// Used as a multiplier for the production.
69    ///
70    /// The highest given production value will be multiplied by this value.
71    pub production_multiplier: Option<f64>,
72
73    /// The amount of storage available at the starting level.
74    pub storage: Option<Vec<StorageConfig>>,
75
76    /// Used as a multiplier for the storage.
77    pub storage_multiplier: Option<f64>,
78
79    /// Cost for each level
80    /// They are the costs to level up from the current level to the next level
81    /// The first element is the cost to level up from 0 to 1
82    pub cost: Vec<HashMap<String, usize>>,
83
84    /// Used as a multiplier for the cost.
85    ///
86    /// The highest given cost value will be multiplied by this value.
87    pub cost_multiplier: Option<f64>,
88}
89
90impl GalaxyConfig {
91    /// Get the production for a single structure at a given level.
92    pub fn get_structure_production(&self, structure: &str, level: usize) -> ProductionConfig {
93        if let Some(structure) = self.systems.structures.get(&structure.to_lowercase()) {
94            structure.get_production(level)
95        } else {
96            ProductionConfig::default()
97        }
98    }
99
100    /// Get the storage for a single structure at a given level.
101    pub fn get_structure_storage(&self, structure: &str, level: usize) -> StorageConfig {
102        if let Some(structure) = self.systems.structures.get(&structure.to_lowercase()) {
103            structure.get_storage(level)
104        } else {
105            StorageConfig::default()
106        }
107    }
108}
109
110impl StructureConfig {
111    /// Get the cost to build this structure at a given level
112    pub fn get_cost(&self, level: usize) -> Cost {
113        // Adjust for the starting level
114        let index = if let Some(lvl) = self.starting_level {
115            level - lvl
116        } else {
117            level
118        };
119        if index < self.cost.len() {
120            Cost::from_map(&self.cost[index])
121        } else if let Some(multiplier) = self.cost_multiplier {
122            // Get the last entry in the cost vector and it's index
123            let (last_level, last_cost) = self.cost.iter().enumerate().last().unwrap();
124            let exponent = index - last_level;
125            let multiplier = multiplier.powi(exponent as i32);
126            let mut cost = last_cost.clone();
127            for (_, value) in cost.iter_mut() {
128                *value = (*value as f64 * multiplier) as usize;
129            }
130            Cost::from_map(&cost)
131        } else {
132            panic!("No cost found for level {}", level);
133        }
134    }
135
136    /// Get the production for this structure at a given level.
137    pub fn get_production(&self, level: usize) -> ProductionConfig {
138        // Adjust for the starting level
139        let index = if let Some(lvl) = self.starting_level {
140            level - lvl
141        } else {
142            level
143        };
144        if let Some(production) = &self.production {
145            if index < production.len() {
146                production[index].clone()
147            } else if let Some(multiplier) = self.production_multiplier {
148                // Get the last entry in the production vector and its index
149                let (last_level, last_production) = production.iter().enumerate().last().unwrap();
150                let exponent = index - last_level;
151                let multiplier = multiplier.powi(exponent as i32);
152                let mut production = last_production.clone();
153                if let Some(metal) = production.metal {
154                    production.metal = Some((metal as f64 * multiplier) as usize);
155                }
156                if let Some(crew) = production.crew {
157                    production.crew = Some((crew as f64 * multiplier) as usize);
158                }
159                if let Some(water) = production.water {
160                    production.water = Some((water as f64 * multiplier) as usize);
161                }
162                production.clone()
163            } else {
164                panic!("No production found for level {}", level);
165            }
166        } else {
167            ProductionConfig::default()
168        }
169    }
170
171    /// Get the storage for this structure at a given level.
172    pub fn get_storage(&self, level: usize) -> StorageConfig {
173        // Adjust for the starting level
174        let index = if let Some(lvl) = self.starting_level {
175            level - lvl
176        } else {
177            level
178        };
179        if let Some(storage) = &self.storage {
180            if index < storage.len() {
181                storage[index].clone()
182            } else if let Some(multiplier) = self.storage_multiplier {
183                // Get the last entry in the storage vector and its index
184                let (last_level, last_storage) = storage.iter().enumerate().last().unwrap();
185                let exponent = index - last_level;
186                let multiplier = multiplier.powi(exponent as i32);
187                let mut storage = last_storage.clone();
188                if let Some(metal) = storage.metal {
189                    storage.metal = Some((metal as f64 * multiplier) as usize);
190                }
191                if let Some(crew) = storage.crew {
192                    storage.crew = Some((crew as f64 * multiplier) as usize);
193                }
194                if let Some(water) = storage.water {
195                    storage.water = Some((water as f64 * multiplier) as usize);
196                }
197                storage.clone()
198            } else {
199                panic!("No storage found for level {}", level);
200            }
201        } else {
202            StorageConfig::default()
203        }
204    }
205}