1use std::borrow::Cow;
2use std::collections::HashMap;
3use std::sync::LazyLock;
4
5use crate::game_types::BuoyancyState;
6use crate::game_types::CameraMode;
7use crate::game_types::CollisionType;
8use crate::game_types::Consumable;
9use crate::game_types::ControlPointType;
10use crate::game_types::DamageStatCategory;
11use crate::game_types::DamageStatWeapon;
12use crate::game_types::DeathCause;
13use crate::game_types::FinishType;
14use crate::game_types::InteractiveZoneType;
15use crate::game_types::ShellHitType;
16use crate::game_types::WeaponType;
17
18pub static DEFAULT_BATTLE_CONSTANTS: LazyLock<BattleConstants> = LazyLock::new(BattleConstants::defaults);
20
21pub static DEFAULT_SHIPS_CONSTANTS: LazyLock<ShipsConstants> = LazyLock::new(ShipsConstants::defaults);
23
24pub static DEFAULT_COMMON_CONSTANTS: LazyLock<CommonConstants> = LazyLock::new(CommonConstants::defaults);
26
27#[derive(Clone)]
29pub struct BattleConstants {
30 camera_modes: HashMap<i32, Cow<'static, str>>,
31 death_reasons: HashMap<i32, Cow<'static, str>>,
32 game_modes: HashMap<i32, Cow<'static, str>>,
33 battle_results: HashMap<i32, Cow<'static, str>>,
34 player_relations: HashMap<i32, Cow<'static, str>>,
35 damage_modules: HashMap<i32, Cow<'static, str>>,
36 finish_types: HashMap<i32, Cow<'static, str>>,
37 consumable_states: HashMap<i32, Cow<'static, str>>,
38 planes_types: HashMap<i32, Cow<'static, str>>,
39 diplomacy_relations: HashMap<i32, Cow<'static, str>>,
40 modules_states: HashMap<i32, Cow<'static, str>>,
41 entity_types: HashMap<i32, Cow<'static, str>>,
42 entity_states: HashMap<i32, Cow<'static, str>>,
43 battery_states: HashMap<i32, Cow<'static, str>>,
44 depth_states: HashMap<i32, Cow<'static, str>>,
45 building_types: HashMap<i32, Cow<'static, str>>,
46 torpedo_marker_types: HashMap<i32, Cow<'static, str>>,
47 interactive_zone_types: HashMap<i32, Cow<'static, str>>,
48 control_point_types: HashMap<i32, Cow<'static, str>>,
49 damage_stat_weapons: HashMap<i32, Cow<'static, str>>,
50 damage_stat_categories: HashMap<i32, Cow<'static, str>>,
51}
52
53impl BattleConstants {
54 #[cfg(feature = "parsing")]
57 pub fn from_xml(xml: &[u8]) -> Self {
58 let xml_str = match std::str::from_utf8(xml) {
59 Ok(s) => s,
60 Err(_) => return Self::defaults(),
61 };
62
63 let defaults = Self::defaults();
64 Self {
65 camera_modes: parse_integer_enum(xml_str, "CAMERA_MODE").unwrap_or(defaults.camera_modes),
66 death_reasons: parse_positional_enum(xml_str, "DEATH_REASON_NAME").unwrap_or(defaults.death_reasons),
67 game_modes: parse_integer_enum(xml_str, "GAME_MODE").unwrap_or(defaults.game_modes),
68 battle_results: parse_integer_enum(xml_str, "BATTLE_RESULT").unwrap_or(defaults.battle_results),
69 player_relations: parse_integer_enum(xml_str, "PLAYER_RELATION").unwrap_or(defaults.player_relations),
70 damage_modules: parse_integer_enum(xml_str, "DAMAGE_MODULES").unwrap_or(defaults.damage_modules),
71 finish_types: parse_integer_enum(xml_str, "FINISH_TYPE").unwrap_or(defaults.finish_types),
72 consumable_states: parse_integer_enum(xml_str, "CONSUMABLE_STATES").unwrap_or(defaults.consumable_states),
73 planes_types: parse_integer_enum(xml_str, "PLANES_TYPES").unwrap_or(defaults.planes_types),
74 diplomacy_relations: parse_integer_enum(xml_str, "DIPLOMACY_RELATIONS")
75 .unwrap_or(defaults.diplomacy_relations),
76 modules_states: parse_integer_enum(xml_str, "MODULES_STATES").unwrap_or(defaults.modules_states),
77 entity_types: parse_integer_enum(xml_str, "ENTITY_TYPES").unwrap_or(defaults.entity_types),
78 entity_states: parse_integer_enum(xml_str, "ENTITY_STATES").unwrap_or(defaults.entity_states),
79 battery_states: parse_integer_enum(xml_str, "BATTERY_STATE").unwrap_or(defaults.battery_states),
80 depth_states: parse_integer_enum(xml_str, "DEPTH_STATE").unwrap_or(defaults.depth_states),
81 building_types: parse_positional_enum(xml_str, "BUILDING_TYPES").unwrap_or(defaults.building_types),
82 torpedo_marker_types: parse_positional_enum(xml_str, "TORPEDO_MARKER_TYPE")
83 .unwrap_or(defaults.torpedo_marker_types),
84 interactive_zone_types: defaults.interactive_zone_types,
85 control_point_types: defaults.control_point_types,
86 damage_stat_weapons: defaults.damage_stat_weapons,
87 damage_stat_categories: defaults.damage_stat_categories,
88 }
89 }
90
91 pub fn defaults() -> Self {
93 Self {
94 camera_modes: HashMap::from([
95 (1, Cow::Borrowed(CameraMode::Airplanes.name())),
96 (2, Cow::Borrowed(CameraMode::Dock.name())),
97 (3, Cow::Borrowed(CameraMode::OverheadMap.name())),
98 (4, Cow::Borrowed(CameraMode::DevFree.name())),
99 (5, Cow::Borrowed(CameraMode::FollowingShells.name())),
100 (6, Cow::Borrowed(CameraMode::FollowingPlanes.name())),
101 (7, Cow::Borrowed(CameraMode::DockModule.name())),
102 (8, Cow::Borrowed(CameraMode::FollowingShip.name())),
103 (9, Cow::Borrowed(CameraMode::FreeFlying.name())),
104 (10, Cow::Borrowed(CameraMode::ReplayFpc.name())),
105 (11, Cow::Borrowed(CameraMode::FollowingSubmarine.name())),
106 (12, Cow::Borrowed(CameraMode::TacticalConsumables.name())),
107 (13, Cow::Borrowed(CameraMode::RespawnMap.name())),
108 (19, Cow::Borrowed(CameraMode::DockFlags.name())),
109 (20, Cow::Borrowed(CameraMode::DockEnsign.name())),
110 (21, Cow::Borrowed(CameraMode::DockLootbox.name())),
111 (22, Cow::Borrowed(CameraMode::DockNavalFlag.name())),
112 (23, Cow::Borrowed(CameraMode::IdleGame.name())),
113 ]),
114 death_reasons: HashMap::from([
115 (0, Cow::Borrowed(DeathCause::None.name())),
116 (1, Cow::Borrowed(DeathCause::Artillery.name())),
117 (2, Cow::Borrowed(DeathCause::Secondaries.name())),
118 (3, Cow::Borrowed(DeathCause::Torpedo.name())),
119 (4, Cow::Borrowed(DeathCause::DiveBomber.name())),
120 (5, Cow::Borrowed(DeathCause::AerialTorpedo.name())),
121 (6, Cow::Borrowed(DeathCause::Fire.name())),
122 (7, Cow::Borrowed(DeathCause::Ramming.name())),
123 (8, Cow::Borrowed(DeathCause::Terrain.name())),
124 (9, Cow::Borrowed(DeathCause::Flooding.name())),
125 (10, Cow::Borrowed(DeathCause::Mirror.name())),
126 (11, Cow::Borrowed(DeathCause::SeaMine.name())),
127 (12, Cow::Borrowed(DeathCause::Special.name())),
128 (13, Cow::Borrowed(DeathCause::DepthCharge.name())),
129 (14, Cow::Borrowed(DeathCause::AerialRocket.name())),
130 (15, Cow::Borrowed(DeathCause::Detonation.name())),
131 (16, Cow::Borrowed(DeathCause::Health.name())),
132 (17, Cow::Borrowed(DeathCause::ApShell.name())),
133 (18, Cow::Borrowed(DeathCause::HeShell.name())),
134 (19, Cow::Borrowed(DeathCause::CsShell.name())),
135 (20, Cow::Borrowed(DeathCause::Fel.name())),
136 (21, Cow::Borrowed(DeathCause::Portal.name())),
137 (22, Cow::Borrowed(DeathCause::SkipBombs.name())),
138 (23, Cow::Borrowed(DeathCause::SectorWave.name())),
139 (24, Cow::Borrowed(DeathCause::Acid.name())),
140 (25, Cow::Borrowed(DeathCause::Laser.name())),
141 (26, Cow::Borrowed(DeathCause::Match.name())),
142 (27, Cow::Borrowed(DeathCause::Timer.name())),
143 (28, Cow::Borrowed(DeathCause::AerialDepthCharge.name())),
144 (29, Cow::Borrowed(DeathCause::Event1.name())),
145 (30, Cow::Borrowed(DeathCause::Event2.name())),
146 (31, Cow::Borrowed(DeathCause::Event3.name())),
147 (32, Cow::Borrowed(DeathCause::Event4.name())),
148 (33, Cow::Borrowed(DeathCause::Event5.name())),
149 (34, Cow::Borrowed(DeathCause::Event6.name())),
150 (35, Cow::Borrowed(DeathCause::Missile.name())),
151 ]),
152 game_modes: HashMap::from([
153 (-1, Cow::Borrowed("INVALID")),
154 (0, Cow::Borrowed("TEST")),
155 (1, Cow::Borrowed("STANDART")),
156 (2, Cow::Borrowed("SINGLEBASE")),
157 (7, Cow::Borrowed("DOMINATION")),
158 (8, Cow::Borrowed("TUTORIAL")),
159 (9, Cow::Borrowed("MEGABASE")),
160 (10, Cow::Borrowed("FORTS")),
161 (11, Cow::Borrowed("STANDARD_DOMINATION")),
162 (12, Cow::Borrowed("EPICENTER")),
163 (13, Cow::Borrowed("ASSAULT_DEFENSE")),
164 (14, Cow::Borrowed("PVE")),
165 (15, Cow::Borrowed("ARMS_RACE")),
166 (16, Cow::Borrowed("EPICENTER_RING")),
167 (17, Cow::Borrowed("ANTI_STANDARD")),
168 (18, Cow::Borrowed("ATTACK_DEFENSE")),
169 (19, Cow::Borrowed("TORPEDO_BEAT")),
170 (20, Cow::Borrowed("TEAM_BATTLE_ROYALE")),
171 (21, Cow::Borrowed("ESCAPE_TO_PORTAL")),
172 (22, Cow::Borrowed("DOMINATION_ASYMM")),
173 (23, Cow::Borrowed("KEY_BATTLE")),
174 (24, Cow::Borrowed("PORTAL_2021")),
175 (25, Cow::Borrowed("TEAM_BATTLE_ROYALE_2021")),
176 (26, Cow::Borrowed("CONVOY_EVENT")),
177 (27, Cow::Borrowed("CONVOY_AIRSHIP")),
178 (28, Cow::Borrowed("TWO_TEAMS_BATTLE_ROYALE")),
179 (29, Cow::Borrowed("PINATA_EVENT")),
180 (30, Cow::Borrowed("RESPAWNS")),
181 (31, Cow::Borrowed("RESPAWNS_SECTORS")),
182 ]),
183 battle_results: HashMap::from([
184 (0, Cow::Borrowed("DEFEAT")),
185 (1, Cow::Borrowed("VICTORY")),
186 (2, Cow::Borrowed("DRAW")),
187 (3, Cow::Borrowed("SUCCESS")),
188 (4, Cow::Borrowed("FAILURE")),
189 (5, Cow::Borrowed("PORTAL")),
190 (6, Cow::Borrowed("MATCH")),
191 (7, Cow::Borrowed("DEATH")),
192 (8, Cow::Borrowed("TEAM_LADDER_WINNER")),
193 (9, Cow::Borrowed("TEAM_LADDER_LOSER")),
194 ]),
195 player_relations: HashMap::from([
196 (0, Cow::Borrowed("SELF")),
197 (1, Cow::Borrowed("ALLY")),
198 (2, Cow::Borrowed("ENEMY")),
199 (3, Cow::Borrowed("NEUTRAL")),
200 ]),
201 damage_modules: HashMap::from([
202 (0, Cow::Borrowed("ENGINE")),
203 (1, Cow::Borrowed("MAIN_CALIBER")),
204 (2, Cow::Borrowed("ATBA_GUN")),
205 (3, Cow::Borrowed("AVIATION")),
206 (4, Cow::Borrowed("AIR_DEFENSE")),
207 (5, Cow::Borrowed("OBSERVATION")),
208 (6, Cow::Borrowed("TORPEDO_TUBE")),
209 (7, Cow::Borrowed("PATH_CONTROL")),
210 (8, Cow::Borrowed("DEPTH_CHARGE_GUN")),
211 (9, Cow::Borrowed("BURN")),
212 (10, Cow::Borrowed("FLOOD")),
213 (11, Cow::Borrowed("ACID")),
214 (12, Cow::Borrowed("HEATED")),
215 (13, Cow::Borrowed("WAVED")),
216 (14, Cow::Borrowed("PINGER")),
217 (15, Cow::Borrowed("OIL_LEAK")),
218 (16, Cow::Borrowed("OIL_LEAK_PENDING")),
219 (17, Cow::Borrowed("WILD_FIRE")),
220 ]),
221 finish_types: HashMap::from([
222 (0, Cow::Borrowed(FinishType::Unknown.name())),
223 (1, Cow::Borrowed(FinishType::Extermination.name())),
224 (2, Cow::Borrowed(FinishType::BaseCaptured.name())),
225 (3, Cow::Borrowed(FinishType::Timeout.name())),
226 (4, Cow::Borrowed(FinishType::Failure.name())),
227 (5, Cow::Borrowed(FinishType::Technical.name())),
228 (8, Cow::Borrowed(FinishType::Score.name())),
229 (9, Cow::Borrowed(FinishType::ScoreOnTimeout.name())),
230 (10, Cow::Borrowed(FinishType::PveMainTaskSucceeded.name())),
231 (11, Cow::Borrowed(FinishType::PveMainTaskFailed.name())),
232 (12, Cow::Borrowed(FinishType::ScoreZero.name())),
233 (13, Cow::Borrowed(FinishType::ScoreExcess.name())),
234 ]),
235 consumable_states: HashMap::from([
236 (0, Cow::Borrowed("READY")),
237 (1, Cow::Borrowed("SELECTED")),
238 (2, Cow::Borrowed("AT_WORK")),
239 (3, Cow::Borrowed("RELOAD")),
240 (4, Cow::Borrowed("NO_AMMO")),
241 (5, Cow::Borrowed("PREPARATION")),
242 (6, Cow::Borrowed("REGENERATION")),
243 ]),
244 planes_types: HashMap::from([
245 (0, Cow::Borrowed("SCOUT")),
246 (1, Cow::Borrowed("DIVEBOMBER")),
247 (2, Cow::Borrowed("TORPEDOBOMBER")),
248 (3, Cow::Borrowed("FIGHTER")),
249 (4, Cow::Borrowed("AUXILIARY")),
250 (5, Cow::Borrowed("SKIP_BOMBER")),
251 (6, Cow::Borrowed("AIR_SUPPORT")),
252 (7, Cow::Borrowed("AIRSHIP")),
253 ]),
254 diplomacy_relations: HashMap::from([
255 (0, Cow::Borrowed("SELF")),
256 (1, Cow::Borrowed("ALLY")),
257 (2, Cow::Borrowed("NEUTRAL")),
258 (3, Cow::Borrowed("ENEMY")),
259 (4, Cow::Borrowed("AGGRESSOR")),
260 ]),
261 modules_states: HashMap::from([
262 (0, Cow::Borrowed("NORMAL")),
263 (1, Cow::Borrowed("DAMAGED")),
264 (2, Cow::Borrowed("CRIT")),
265 (3, Cow::Borrowed("BROKEN")),
266 (4, Cow::Borrowed("DEAD")),
267 ]),
268 entity_types: HashMap::from([
269 (-1, Cow::Borrowed("INVALID")),
270 (0, Cow::Borrowed("SHIP")),
271 (1, Cow::Borrowed("PLANE")),
272 (2, Cow::Borrowed("TORPEDO")),
273 (3, Cow::Borrowed("BUILDING")),
274 (11, Cow::Borrowed("CAPTURE_POINT")),
275 (12, Cow::Borrowed("PLAYER")),
276 (13, Cow::Borrowed("EPICENTER")),
277 (14, Cow::Borrowed("SCENARIO_OBJECT")),
278 (15, Cow::Borrowed("DROP_ZONE")),
279 (16, Cow::Borrowed("ATTENTION_POINT")),
280 (17, Cow::Borrowed("KEY_OBJECT")),
281 (18, Cow::Borrowed("INTERACTIVE_ZONE")),
282 (27, Cow::Borrowed("PINATA_SHIP")),
283 (28, Cow::Borrowed("STARTREK_SCRAP")),
284 (29, Cow::Borrowed("MISSILE")),
285 (99, Cow::Borrowed("NAVPOINT")),
286 (100, Cow::Borrowed("EMPTY")),
287 ]),
288 entity_states: HashMap::from([
289 (0, Cow::Borrowed("EMPTY")),
290 (1, Cow::Borrowed("REPAIR")),
291 (2, Cow::Borrowed("GATHERING_SURVIVORS")),
292 (3, Cow::Borrowed("FILTH")),
293 (4, Cow::Borrowed("FROZEN")),
294 (5, Cow::Borrowed("UNLOADING_MARINES")),
295 (6, Cow::Borrowed("INSIDE_WEATHER")),
296 (7, Cow::Borrowed("NEAR_WEATHER")),
297 (8, Cow::Borrowed("ILLUMINATED")),
298 (9, Cow::Borrowed("BY_NIGHT")),
299 (10, Cow::Borrowed("INSIDE_MINEFIELD")),
300 (11, Cow::Borrowed("NEAR_MINEFIELD")),
301 (12, Cow::Borrowed("CAPTURING_LOCKED")),
302 (13, Cow::Borrowed("DANGER")),
303 (14, Cow::Borrowed("TEAM_01")),
304 (15, Cow::Borrowed("TEAM_02")),
305 (16, Cow::Borrowed("TEAM_03")),
306 (17, Cow::Borrowed("TEAM_11")),
307 (18, Cow::Borrowed("TEAM_12")),
308 (19, Cow::Borrowed("TEAM_13")),
309 (20, Cow::Borrowed("TEAM_21")),
310 (21, Cow::Borrowed("TEAM_22")),
311 (22, Cow::Borrowed("TEAM_23")),
312 (23, Cow::Borrowed("TEAM_31")),
313 (24, Cow::Borrowed("TEAM_32")),
314 (25, Cow::Borrowed("TEAM_33")),
315 (26, Cow::Borrowed("SPOTTED_BY_ENEMY")),
316 (27, Cow::Borrowed("INVULNERABLE")),
317 (28, Cow::Borrowed("FLAGSHIP")),
318 (29, Cow::Borrowed("MIGNON")),
319 (30, Cow::Borrowed("REPAIR_SHIP")),
320 (100, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_BROKEN_MODULES")),
321 (101, Cow::Borrowed("BURN")),
322 (102, Cow::Borrowed("FLOOD")),
323 (103, Cow::Borrowed("HOLD_RESOURCE")),
324 (104, Cow::Borrowed("HOLD_RESOURCE_FILTHIOR_TEAM_0")),
325 (105, Cow::Borrowed("HOLD_RESOURCE_FILTHIOR_TEAM_1")),
326 (106, Cow::Borrowed("HOLD_RESOURCE_FILTHIOR_TEAM_2")),
327 (107, Cow::Borrowed("HOLD_RESOURCE_FILTHIOR_TEAM_3")),
328 (108, Cow::Borrowed("HOLD_RESOURCE_POINTS")),
329 (109, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_CRIT_MODULES")),
330 (110, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_SPECIAL_MODULES")),
331 (111, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_MODIFIERS")),
332 (112, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_TALENTS")),
333 (113, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_ATBA_ACCURACY_PERK")),
334 (114, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_PERKS")),
335 (115, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_BUFFS")),
336 (116, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_WEATHER")),
337 (117, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_INTERACTIVE_ZONE")),
338 (118, Cow::Borrowed("EMERGENCY_SURFACING")),
339 (119, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_BATTERY_STATE")),
340 (120, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_DEPTH")),
341 (121, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_ARTILLERY_FIRE_MODE")),
342 (122, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_RAGE_MODE")),
343 (123, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_CONSUMABLES")),
344 (124, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_NOT_SPECIAL_MODULES")),
345 (125, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_CONSUMABLE_LOCKER")),
346 (126, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_ANTI_ABUSE_SYSTEM")),
347 (127, Cow::Borrowed("BATTLE_CARD_SELECTOR_AVAILABLE")),
348 (128, Cow::Borrowed("SHIP_PARAMS_CHANGE_BY_INNATE_SKILLS")),
349 ]),
350 battery_states: HashMap::from([
351 (0, Cow::Borrowed("IDLE")),
352 (1, Cow::Borrowed("CHARGING")),
353 (2, Cow::Borrowed("FROZEN")),
354 (3, Cow::Borrowed("SPENDING_NORMAL")),
355 (4, Cow::Borrowed("SPENDING_WARNING")),
356 (5, Cow::Borrowed("SPENDING_CRITICAL")),
357 (6, Cow::Borrowed("BURNING")),
358 (7, Cow::Borrowed("EMPTY")),
359 ]),
360 depth_states: HashMap::from([
361 (-1, Cow::Borrowed(BuoyancyState::Invalid.name())),
362 (0, Cow::Borrowed(BuoyancyState::Surface.name())),
363 (1, Cow::Borrowed(BuoyancyState::Periscope.name())),
364 (2, Cow::Borrowed(BuoyancyState::SemiDeepWater.name())),
365 (3, Cow::Borrowed(BuoyancyState::DeepWater.name())),
366 (4, Cow::Borrowed(BuoyancyState::DeepWaterInvul.name())),
367 ]),
368 building_types: HashMap::from([
369 (0, Cow::Borrowed("ANTI_AIRCRAFT")),
370 (1, Cow::Borrowed("AIR_BASE")),
371 (2, Cow::Borrowed("COASTAL_ARTILLERY")),
372 (3, Cow::Borrowed("MILITARY")),
373 (4, Cow::Borrowed("SENSOR_TOWER")),
374 (5, Cow::Borrowed("COMPLEX")),
375 (6, Cow::Borrowed("RAY_TOWER")),
376 (7, Cow::Borrowed("GENERATOR")),
377 (8, Cow::Borrowed("SPACE_STATION")),
378 ]),
379 torpedo_marker_types: HashMap::from([
380 (0, Cow::Borrowed("NORMAL")),
381 (1, Cow::Borrowed("DEEP_WATER")),
382 (2, Cow::Borrowed("ACOUSTIC")),
383 (3, Cow::Borrowed("MAGNETIC")),
384 (4, Cow::Borrowed("NOT_DANGEROUS")),
385 ]),
386 interactive_zone_types: HashMap::from([
387 (0, Cow::Borrowed(InteractiveZoneType::NoType.name())),
388 (1, Cow::Borrowed(InteractiveZoneType::ResourceZone.name())),
389 (2, Cow::Borrowed(InteractiveZoneType::ConvoyZone.name())),
390 (3, Cow::Borrowed(InteractiveZoneType::RepairZone.name())),
391 (4, Cow::Borrowed(InteractiveZoneType::FelZone.name())),
392 (5, Cow::Borrowed(InteractiveZoneType::WeatherZone.name())),
393 (6, Cow::Borrowed(InteractiveZoneType::DropZone.name())),
394 (7, Cow::Borrowed(InteractiveZoneType::ConsumableZone.name())),
395 (8, Cow::Borrowed(InteractiveZoneType::ColoredByRelation.name())),
396 (9, Cow::Borrowed(InteractiveZoneType::ControlPoint.name())),
397 (10, Cow::Borrowed(InteractiveZoneType::RescueZone.name())),
398 (11, Cow::Borrowed(InteractiveZoneType::OrbitalStrikeZone.name())),
399 ]),
400 control_point_types: HashMap::from([
401 (1, Cow::Borrowed(ControlPointType::Control.name())),
402 (2, Cow::Borrowed(ControlPointType::Base.name())),
403 (3, Cow::Borrowed(ControlPointType::MegaBase.name())),
404 (4, Cow::Borrowed(ControlPointType::BuildingCp.name())),
405 (5, Cow::Borrowed(ControlPointType::BaseWithPoints.name())),
406 (6, Cow::Borrowed(ControlPointType::EpicenterCp.name())),
407 ]),
408 damage_stat_weapons: HashMap::from([
410 (0, Cow::Borrowed(DamageStatWeapon::Default.name())),
411 (1, Cow::Borrowed(DamageStatWeapon::MainAp.name())),
412 (2, Cow::Borrowed(DamageStatWeapon::MainHe.name())),
413 (3, Cow::Borrowed(DamageStatWeapon::AtbaAp.name())),
414 (4, Cow::Borrowed(DamageStatWeapon::AtbaHe.name())),
415 (5, Cow::Borrowed(DamageStatWeapon::MainAiAp.name())),
416 (6, Cow::Borrowed(DamageStatWeapon::MainAiHe.name())),
417 (7, Cow::Borrowed(DamageStatWeapon::Torpedo.name())),
418 (8, Cow::Borrowed(DamageStatWeapon::Antiair.name())),
419 (9, Cow::Borrowed(DamageStatWeapon::Scout.name())),
420 (10, Cow::Borrowed(DamageStatWeapon::BomberAp.name())),
421 (11, Cow::Borrowed(DamageStatWeapon::BomberHe.name())),
422 (12, Cow::Borrowed(DamageStatWeapon::TBomber.name())),
423 (13, Cow::Borrowed(DamageStatWeapon::Fighter.name())),
424 (14, Cow::Borrowed(DamageStatWeapon::SFighter.name())),
425 (15, Cow::Borrowed(DamageStatWeapon::Turret.name())),
426 (16, Cow::Borrowed(DamageStatWeapon::Spot.name())),
427 (17, Cow::Borrowed(DamageStatWeapon::Burn.name())),
428 (18, Cow::Borrowed(DamageStatWeapon::Ram.name())),
429 (19, Cow::Borrowed(DamageStatWeapon::Terrain.name())),
430 (20, Cow::Borrowed(DamageStatWeapon::Flood.name())),
431 (21, Cow::Borrowed(DamageStatWeapon::Mirror.name())),
432 (22, Cow::Borrowed(DamageStatWeapon::Radar.name())),
433 (23, Cow::Borrowed(DamageStatWeapon::Xray.name())),
434 (24, Cow::Borrowed(DamageStatWeapon::ConsSpot.name())),
435 (25, Cow::Borrowed(DamageStatWeapon::SeaMine.name())),
436 (26, Cow::Borrowed(DamageStatWeapon::Fel.name())),
437 (27, Cow::Borrowed(DamageStatWeapon::DepthCharge.name())),
438 (28, Cow::Borrowed(DamageStatWeapon::RocketHe.name())),
439 (29, Cow::Borrowed(DamageStatWeapon::AaNear.name())),
440 (30, Cow::Borrowed(DamageStatWeapon::AaMedium.name())),
441 (31, Cow::Borrowed(DamageStatWeapon::AaFar.name())),
442 (32, Cow::Borrowed(DamageStatWeapon::MainCs.name())),
443 (33, Cow::Borrowed(DamageStatWeapon::AtbaCs.name())),
444 (34, Cow::Borrowed(DamageStatWeapon::Portal.name())),
445 (35, Cow::Borrowed(DamageStatWeapon::TorpedoAcc.name())),
446 (36, Cow::Borrowed(DamageStatWeapon::TorpedoMag.name())),
447 (37, Cow::Borrowed(DamageStatWeapon::Ping.name())),
448 (38, Cow::Borrowed(DamageStatWeapon::PingSlow.name())),
449 (39, Cow::Borrowed(DamageStatWeapon::PingFast.name())),
450 (40, Cow::Borrowed(DamageStatWeapon::TorpedoAccOff.name())),
451 (41, Cow::Borrowed(DamageStatWeapon::RocketAp.name())),
452 (42, Cow::Borrowed(DamageStatWeapon::SkipHe.name())),
453 (43, Cow::Borrowed(DamageStatWeapon::SkipAp.name())),
454 (44, Cow::Borrowed(DamageStatWeapon::Acid.name())),
455 (45, Cow::Borrowed(DamageStatWeapon::SectorWave.name())),
456 (46, Cow::Borrowed(DamageStatWeapon::Match.name())),
457 (47, Cow::Borrowed(DamageStatWeapon::Timer.name())),
458 (48, Cow::Borrowed(DamageStatWeapon::ChargeLaser.name())),
459 (49, Cow::Borrowed(DamageStatWeapon::PulseLaser.name())),
460 (50, Cow::Borrowed(DamageStatWeapon::AxisLaser.name())),
461 (51, Cow::Borrowed(DamageStatWeapon::BomberApAsup.name())),
462 (52, Cow::Borrowed(DamageStatWeapon::BomberHeAsup.name())),
463 (53, Cow::Borrowed(DamageStatWeapon::TBomberAsup.name())),
464 (54, Cow::Borrowed(DamageStatWeapon::RocketHeAsup.name())),
465 (55, Cow::Borrowed(DamageStatWeapon::RocketApAsup.name())),
466 (56, Cow::Borrowed(DamageStatWeapon::SkipHeAsup.name())),
467 (57, Cow::Borrowed(DamageStatWeapon::SkipApAsup.name())),
468 (58, Cow::Borrowed(DamageStatWeapon::DepthChargeAsup.name())),
469 (59, Cow::Borrowed(DamageStatWeapon::TorpedoDeep.name())),
470 (60, Cow::Borrowed(DamageStatWeapon::TorpedoAlter.name())),
471 (61, Cow::Borrowed(DamageStatWeapon::AirSupport.name())),
472 (62, Cow::Borrowed(DamageStatWeapon::BomberApAlter.name())),
473 (63, Cow::Borrowed(DamageStatWeapon::BomberHeAlter.name())),
474 (64, Cow::Borrowed(DamageStatWeapon::TBomberAlter.name())),
475 (65, Cow::Borrowed(DamageStatWeapon::RocketHeAlter.name())),
476 (66, Cow::Borrowed(DamageStatWeapon::RocketApAlter.name())),
477 (67, Cow::Borrowed(DamageStatWeapon::SkipHeAlter.name())),
478 (68, Cow::Borrowed(DamageStatWeapon::SkipApAlter.name())),
479 (69, Cow::Borrowed(DamageStatWeapon::DepthChargeAlter.name())),
480 (70, Cow::Borrowed(DamageStatWeapon::Recon.name())),
481 (71, Cow::Borrowed(DamageStatWeapon::BomberApTc.name())),
482 (72, Cow::Borrowed(DamageStatWeapon::BomberHeTc.name())),
483 (73, Cow::Borrowed(DamageStatWeapon::TBomberTc.name())),
484 (74, Cow::Borrowed(DamageStatWeapon::RocketHeTc.name())),
485 (75, Cow::Borrowed(DamageStatWeapon::RocketApTc.name())),
486 (76, Cow::Borrowed(DamageStatWeapon::SkipHeTc.name())),
487 (77, Cow::Borrowed(DamageStatWeapon::SkipApTc.name())),
488 (78, Cow::Borrowed(DamageStatWeapon::DepthChargeTc.name())),
489 (79, Cow::Borrowed(DamageStatWeapon::PhaserLaser.name())),
490 (80, Cow::Borrowed(DamageStatWeapon::Event1.name())),
491 (81, Cow::Borrowed(DamageStatWeapon::Event2.name())),
492 (82, Cow::Borrowed(DamageStatWeapon::TorpedoPhoton.name())),
493 (83, Cow::Borrowed(DamageStatWeapon::Missile.name())),
494 (84, Cow::Borrowed(DamageStatWeapon::AntiMissile.name())),
495 ]),
496 damage_stat_categories: HashMap::from([
498 (0, Cow::Borrowed(DamageStatCategory::Enemy.name())),
499 (1, Cow::Borrowed(DamageStatCategory::Ally.name())),
500 (2, Cow::Borrowed(DamageStatCategory::Spot.name())),
501 (3, Cow::Borrowed(DamageStatCategory::Agro.name())),
502 ]),
503 }
504 }
505
506 pub fn camera_mode(&self, id: i32) -> Option<&str> {
507 self.camera_modes.get(&id).map(|s| s.as_ref())
508 }
509
510 pub fn death_reason(&self, id: i32) -> Option<&str> {
511 self.death_reasons.get(&id).map(|s| s.as_ref())
512 }
513
514 pub fn game_mode(&self, id: i32) -> Option<&str> {
515 self.game_modes.get(&id).map(|s| s.as_ref())
516 }
517
518 pub fn battle_result(&self, id: i32) -> Option<&str> {
519 self.battle_results.get(&id).map(|s| s.as_ref())
520 }
521
522 pub fn player_relation(&self, id: i32) -> Option<&str> {
523 self.player_relations.get(&id).map(|s| s.as_ref())
524 }
525
526 pub fn damage_module(&self, id: i32) -> Option<&str> {
527 self.damage_modules.get(&id).map(|s| s.as_ref())
528 }
529
530 pub fn finish_type(&self, id: i32) -> Option<&str> {
531 self.finish_types.get(&id).map(|s| s.as_ref())
532 }
533
534 pub fn consumable_state(&self, id: i32) -> Option<&str> {
535 self.consumable_states.get(&id).map(|s| s.as_ref())
536 }
537
538 pub fn planes_type(&self, id: i32) -> Option<&str> {
539 self.planes_types.get(&id).map(|s| s.as_ref())
540 }
541
542 pub fn diplomacy_relation(&self, id: i32) -> Option<&str> {
543 self.diplomacy_relations.get(&id).map(|s| s.as_ref())
544 }
545
546 pub fn modules_state(&self, id: i32) -> Option<&str> {
547 self.modules_states.get(&id).map(|s| s.as_ref())
548 }
549
550 pub fn entity_type(&self, id: i32) -> Option<&str> {
551 self.entity_types.get(&id).map(|s| s.as_ref())
552 }
553
554 pub fn entity_state(&self, id: i32) -> Option<&str> {
555 self.entity_states.get(&id).map(|s| s.as_ref())
556 }
557
558 pub fn battery_state(&self, id: i32) -> Option<&str> {
559 self.battery_states.get(&id).map(|s| s.as_ref())
560 }
561
562 pub fn depth_state(&self, id: i32) -> Option<&str> {
563 self.depth_states.get(&id).map(|s| s.as_ref())
564 }
565
566 pub fn building_type(&self, id: i32) -> Option<&str> {
567 self.building_types.get(&id).map(|s| s.as_ref())
568 }
569
570 pub fn torpedo_marker_type(&self, id: i32) -> Option<&str> {
571 self.torpedo_marker_types.get(&id).map(|s| s.as_ref())
572 }
573
574 pub fn interactive_zone_type(&self, id: i32) -> Option<&str> {
575 self.interactive_zone_types.get(&id).map(|s| s.as_ref())
576 }
577
578 pub fn control_point_type(&self, id: i32) -> Option<&str> {
579 self.control_point_types.get(&id).map(|s| s.as_ref())
580 }
581
582 pub fn camera_modes_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
583 &mut self.camera_modes
584 }
585
586 pub fn death_reasons_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
587 &mut self.death_reasons
588 }
589
590 pub fn game_modes_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
591 &mut self.game_modes
592 }
593
594 pub fn battle_results_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
595 &mut self.battle_results
596 }
597
598 pub fn player_relations_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
599 &mut self.player_relations
600 }
601
602 pub fn damage_modules_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
603 &mut self.damage_modules
604 }
605
606 pub fn finish_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
607 &mut self.finish_types
608 }
609
610 pub fn consumable_states_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
611 &mut self.consumable_states
612 }
613
614 pub fn planes_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
615 &mut self.planes_types
616 }
617
618 pub fn diplomacy_relations_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
619 &mut self.diplomacy_relations
620 }
621
622 pub fn modules_states_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
623 &mut self.modules_states
624 }
625
626 pub fn entity_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
627 &mut self.entity_types
628 }
629
630 pub fn entity_states_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
631 &mut self.entity_states
632 }
633
634 pub fn battery_states_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
635 &mut self.battery_states
636 }
637
638 pub fn depth_states_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
639 &mut self.depth_states
640 }
641
642 pub fn building_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
643 &mut self.building_types
644 }
645
646 pub fn torpedo_marker_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
647 &mut self.torpedo_marker_types
648 }
649
650 pub fn interactive_zone_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
651 &mut self.interactive_zone_types
652 }
653
654 pub fn control_point_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
655 &mut self.control_point_types
656 }
657
658 pub fn damage_stat_weapon(&self, id: i32) -> Option<&str> {
659 self.damage_stat_weapons.get(&id).map(|s| s.as_ref())
660 }
661
662 pub fn damage_stat_weapons(&self) -> &HashMap<i32, Cow<'static, str>> {
663 &self.damage_stat_weapons
664 }
665
666 pub fn damage_stat_weapons_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
667 &mut self.damage_stat_weapons
668 }
669
670 pub fn damage_stat_category(&self, id: i32) -> Option<&str> {
671 self.damage_stat_categories.get(&id).map(|s| s.as_ref())
672 }
673
674 pub fn damage_stat_categories(&self) -> &HashMap<i32, Cow<'static, str>> {
675 &self.damage_stat_categories
676 }
677
678 pub fn damage_stat_categories_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
679 &mut self.damage_stat_categories
680 }
681
682 pub fn camera_modes(&self) -> &HashMap<i32, Cow<'static, str>> {
683 &self.camera_modes
684 }
685
686 pub fn death_reasons(&self) -> &HashMap<i32, Cow<'static, str>> {
687 &self.death_reasons
688 }
689
690 pub fn game_modes(&self) -> &HashMap<i32, Cow<'static, str>> {
691 &self.game_modes
692 }
693
694 pub fn battle_results(&self) -> &HashMap<i32, Cow<'static, str>> {
695 &self.battle_results
696 }
697
698 pub fn player_relations(&self) -> &HashMap<i32, Cow<'static, str>> {
699 &self.player_relations
700 }
701
702 pub fn damage_modules(&self) -> &HashMap<i32, Cow<'static, str>> {
703 &self.damage_modules
704 }
705
706 pub fn finish_types(&self) -> &HashMap<i32, Cow<'static, str>> {
707 &self.finish_types
708 }
709
710 pub fn consumable_states(&self) -> &HashMap<i32, Cow<'static, str>> {
711 &self.consumable_states
712 }
713
714 pub fn planes_types(&self) -> &HashMap<i32, Cow<'static, str>> {
715 &self.planes_types
716 }
717
718 pub fn diplomacy_relations(&self) -> &HashMap<i32, Cow<'static, str>> {
719 &self.diplomacy_relations
720 }
721
722 pub fn modules_states(&self) -> &HashMap<i32, Cow<'static, str>> {
723 &self.modules_states
724 }
725
726 pub fn entity_types(&self) -> &HashMap<i32, Cow<'static, str>> {
727 &self.entity_types
728 }
729
730 pub fn entity_states(&self) -> &HashMap<i32, Cow<'static, str>> {
731 &self.entity_states
732 }
733
734 pub fn battery_states(&self) -> &HashMap<i32, Cow<'static, str>> {
735 &self.battery_states
736 }
737
738 pub fn depth_states(&self) -> &HashMap<i32, Cow<'static, str>> {
739 &self.depth_states
740 }
741
742 pub fn building_types(&self) -> &HashMap<i32, Cow<'static, str>> {
743 &self.building_types
744 }
745
746 pub fn torpedo_marker_types(&self) -> &HashMap<i32, Cow<'static, str>> {
747 &self.torpedo_marker_types
748 }
749
750 pub fn interactive_zone_types(&self) -> &HashMap<i32, Cow<'static, str>> {
751 &self.interactive_zone_types
752 }
753
754 pub fn control_point_types(&self) -> &HashMap<i32, Cow<'static, str>> {
755 &self.control_point_types
756 }
757}
758
759#[derive(Clone)]
761pub struct ShipsConstants {
762 weapon_types: HashMap<i32, Cow<'static, str>>,
763 module_types: HashMap<i32, Cow<'static, str>>,
764 shell_hit_types: HashMap<i32, Cow<'static, str>>,
765 collision_types: HashMap<i32, Cow<'static, str>>,
766}
767
768impl ShipsConstants {
769 #[cfg(feature = "parsing")]
772 pub fn from_xml(xml: &[u8]) -> Self {
773 let xml_str = match std::str::from_utf8(xml) {
774 Ok(s) => s,
775 Err(_) => return Self::defaults(),
776 };
777
778 let defaults = Self::defaults();
779 Self {
780 weapon_types: parse_integer_enum(xml_str, "SHIP_WEAPON_TYPES").unwrap_or(defaults.weapon_types),
781 module_types: parse_integer_enum(xml_str, "SHIP_MODULE_TYPES").unwrap_or(defaults.module_types),
782 shell_hit_types: defaults.shell_hit_types,
783 collision_types: defaults.collision_types,
784 }
785 }
786
787 pub fn defaults() -> Self {
789 Self {
790 weapon_types: HashMap::from([
791 (-1, Cow::Borrowed("NONE")),
792 (0, Cow::Borrowed(WeaponType::Artillery.name())),
793 (1, Cow::Borrowed(WeaponType::Secondaries.name())),
794 (2, Cow::Borrowed(WeaponType::Torpedoes.name())),
795 (3, Cow::Borrowed(WeaponType::Planes.name())),
796 (4, Cow::Borrowed("AIRDEFENCE")),
797 (5, Cow::Borrowed("DEPTH_CHARGES")),
798 (6, Cow::Borrowed(WeaponType::Pinger.name())),
799 (7, Cow::Borrowed("CHARGE_LASER")),
800 (8, Cow::Borrowed("IMPULSE_LASER")),
801 (9, Cow::Borrowed("AXIS_LASER")),
802 (10, Cow::Borrowed("PHASER_LASER")),
803 (11, Cow::Borrowed("WAVES")),
804 (12, Cow::Borrowed("AIR_SUPPORT")),
805 (13, Cow::Borrowed("ANTI_MISSILE")),
806 (14, Cow::Borrowed("MISSILES")),
807 (100, Cow::Borrowed("SQUADRON")),
808 (200, Cow::Borrowed("PULSE_PHASERS")),
809 ]),
810 module_types: HashMap::from([
811 (0, Cow::Borrowed("ARTILLERY")),
812 (1, Cow::Borrowed("HULL")),
813 (2, Cow::Borrowed("TORPEDOES")),
814 (3, Cow::Borrowed("SUO")),
815 (4, Cow::Borrowed("ENGINE")),
816 (5, Cow::Borrowed("TORPEDO_BOMBER")),
817 (6, Cow::Borrowed("DIVE_BOMBER")),
818 (7, Cow::Borrowed("FIGHTER")),
819 (8, Cow::Borrowed("FLIGHT_CONTROLL")),
820 (9, Cow::Borrowed("HYDROPHONE")),
821 (10, Cow::Borrowed("SKIP_BOMBER")),
822 (11, Cow::Borrowed("PRIMARY_WEAPONS")),
823 (12, Cow::Borrowed("SECONDARY_WEAPONS")),
824 (13, Cow::Borrowed("ABILITIES")),
825 ]),
826 shell_hit_types: HashMap::from([
827 (0, Cow::Borrowed(ShellHitType::Normal.name())),
828 (1, Cow::Borrowed(ShellHitType::Ricochet.name())),
829 (2, Cow::Borrowed(ShellHitType::MajorHit.name())),
830 (3, Cow::Borrowed(ShellHitType::NoPenetration.name())),
831 (4, Cow::Borrowed(ShellHitType::Overpenetration.name())),
832 (5, Cow::Borrowed(ShellHitType::None.name())),
833 (6, Cow::Borrowed(ShellHitType::ExitOverpenetration.name())),
834 (7, Cow::Borrowed(ShellHitType::Underwater.name())),
835 ]),
836 collision_types: HashMap::from([
837 (0, Cow::Borrowed(CollisionType::NoHit.name())),
838 (1, Cow::Borrowed(CollisionType::HitWater.name())),
839 (2, Cow::Borrowed(CollisionType::HitGround.name())),
840 (3, Cow::Borrowed(CollisionType::HitEntity.name())),
841 (4, Cow::Borrowed(CollisionType::HitEntityBB.name())),
842 (5, Cow::Borrowed(CollisionType::HitWave.name())),
843 ]),
844 }
845 }
846
847 pub fn weapon_type(&self, id: i32) -> Option<&str> {
848 self.weapon_types.get(&id).map(|s| s.as_ref())
849 }
850
851 pub fn module_type(&self, id: i32) -> Option<&str> {
852 self.module_types.get(&id).map(|s| s.as_ref())
853 }
854
855 pub fn weapon_types(&self) -> &HashMap<i32, Cow<'static, str>> {
856 &self.weapon_types
857 }
858
859 pub fn module_types(&self) -> &HashMap<i32, Cow<'static, str>> {
860 &self.module_types
861 }
862
863 pub fn weapon_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
864 &mut self.weapon_types
865 }
866
867 pub fn module_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
868 &mut self.module_types
869 }
870
871 pub fn shell_hit_type(&self, id: i32) -> Option<&str> {
872 self.shell_hit_types.get(&id).map(|s| s.as_ref())
873 }
874
875 pub fn collision_type(&self, id: i32) -> Option<&str> {
876 self.collision_types.get(&id).map(|s| s.as_ref())
877 }
878
879 pub fn shell_hit_types(&self) -> &HashMap<i32, Cow<'static, str>> {
880 &self.shell_hit_types
881 }
882
883 pub fn collision_types(&self) -> &HashMap<i32, Cow<'static, str>> {
884 &self.collision_types
885 }
886
887 pub fn shell_hit_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
888 &mut self.shell_hit_types
889 }
890
891 pub fn collision_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
892 &mut self.collision_types
893 }
894}
895
896#[derive(Clone)]
898pub struct WeaponsConstants {
899 gun_states: HashMap<i32, Cow<'static, str>>,
900}
901
902impl WeaponsConstants {
903 #[cfg(feature = "parsing")]
906 pub fn from_xml(xml: &[u8]) -> Self {
907 let xml_str = match std::str::from_utf8(xml) {
908 Ok(s) => s,
909 Err(_) => return Self::defaults(),
910 };
911
912 let defaults = Self::defaults();
913 Self { gun_states: parse_integer_enum(xml_str, "GUN_STATE").unwrap_or(defaults.gun_states) }
914 }
915
916 pub fn defaults() -> Self {
918 Self {
919 gun_states: HashMap::from([
920 (1, Cow::Borrowed("READY")),
921 (2, Cow::Borrowed("WORK")),
922 (3, Cow::Borrowed("RELOAD")),
923 (4, Cow::Borrowed("SWITCHING_AMMO")),
924 (5, Cow::Borrowed("RELOAD_STOPPED")),
925 (6, Cow::Borrowed("CHARGE")),
926 (7, Cow::Borrowed("CRITICAL")),
927 (8, Cow::Borrowed("DESTROYED")),
928 (9, Cow::Borrowed("SWITCHING_CRITICAL")),
929 (10, Cow::Borrowed("DISABLED")),
930 (11, Cow::Borrowed("BROKEN")),
931 ]),
932 }
933 }
934
935 pub fn gun_state(&self, id: i32) -> Option<&str> {
936 self.gun_states.get(&id).map(|s| s.as_ref())
937 }
938
939 pub fn gun_states(&self) -> &HashMap<i32, Cow<'static, str>> {
940 &self.gun_states
941 }
942
943 pub fn gun_states_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
944 &mut self.gun_states
945 }
946}
947
948#[derive(Clone)]
950pub struct CommonConstants {
951 plane_ammo_types: HashMap<i32, Cow<'static, str>>,
952 torpedo_types: HashMap<i32, Cow<'static, str>>,
953 consumable_types: HashMap<i32, Cow<'static, str>>,
954 battle_stages: HashMap<i32, crate::game_types::BattleStage>,
955}
956
957impl CommonConstants {
958 #[cfg(feature = "parsing")]
961 pub fn from_xml(xml: &[u8]) -> Self {
962 let xml_str = match std::str::from_utf8(xml) {
963 Ok(s) => s,
964 Err(_) => return Self::defaults(),
965 };
966
967 let defaults = Self::defaults();
968 Self {
969 plane_ammo_types: parse_integer_enum(xml_str, "PLANE_AMMO_TYPES").unwrap_or(defaults.plane_ammo_types),
970 torpedo_types: parse_integer_enum(xml_str, "TORPEDO_TYPE").unwrap_or(defaults.torpedo_types),
971 consumable_types: defaults.consumable_types,
972 battle_stages: defaults.battle_stages,
973 }
974 }
975
976 pub fn defaults() -> Self {
978 Self {
979 plane_ammo_types: HashMap::from([
980 (-1, Cow::Borrowed("NONE")),
981 (0, Cow::Borrowed("PROJECTILE")),
982 (1, Cow::Borrowed("BOMB_HE")),
983 (2, Cow::Borrowed("BOMB_AP")),
984 (3, Cow::Borrowed("SKIP_BOMB_HE")),
985 (4, Cow::Borrowed("SKIP_BOMB_AP")),
986 (5, Cow::Borrowed("TORPEDO")),
987 (6, Cow::Borrowed("TORPEDO_DEEPWATER")),
988 (7, Cow::Borrowed("PROJECTILE_AP")),
989 (8, Cow::Borrowed("DEPTH_CHARGE")),
990 (9, Cow::Borrowed("MINE")),
991 (10, Cow::Borrowed("SMOKE")),
992 ]),
993 torpedo_types: HashMap::from([
994 (0, Cow::Borrowed("COMMON")),
995 (1, Cow::Borrowed("SUBMARINE")),
996 (2, Cow::Borrowed("PHOTON")),
997 ]),
998 consumable_types: HashMap::from([
999 (0, Cow::Borrowed(Consumable::DamageControl.name())),
1000 (1, Cow::Borrowed(Consumable::SpottingAircraft.name())),
1001 (2, Cow::Borrowed(Consumable::DefensiveAntiAircraft.name())),
1002 (3, Cow::Borrowed(Consumable::SpeedBoost.name())),
1003 (4, Cow::Borrowed(Consumable::MainBatteryReloadBooster.name())),
1004 (6, Cow::Borrowed(Consumable::Smoke.name())),
1005 (8, Cow::Borrowed(Consumable::RepairParty.name())),
1006 (9, Cow::Borrowed(Consumable::CatapultFighter.name())),
1007 (10, Cow::Borrowed(Consumable::HydroacousticSearch.name())),
1008 (11, Cow::Borrowed(Consumable::TorpedoReloadBooster.name())),
1009 (12, Cow::Borrowed(Consumable::Radar.name())),
1010 (13, Cow::Borrowed(Consumable::Trigger1.name())),
1011 (14, Cow::Borrowed(Consumable::Trigger2.name())),
1012 (15, Cow::Borrowed(Consumable::Trigger3.name())),
1013 (16, Cow::Borrowed(Consumable::Trigger4.name())),
1014 (17, Cow::Borrowed(Consumable::Trigger5.name())),
1015 (18, Cow::Borrowed(Consumable::Trigger6.name())),
1016 (19, Cow::Borrowed(Consumable::Invulnerable.name())),
1017 (20, Cow::Borrowed(Consumable::HealForsage.name())),
1018 (21, Cow::Borrowed(Consumable::CallFighters.name())),
1019 (22, Cow::Borrowed(Consumable::RegenerateHealth.name())),
1020 (23, Cow::Borrowed(Consumable::SubsOxygenRegen.name())),
1021 (24, Cow::Borrowed(Consumable::SubsWaveGunBoost.name())),
1022 (25, Cow::Borrowed(Consumable::SubsFourthState.name())),
1023 (26, Cow::Borrowed(Consumable::DepthCharges.name())),
1024 (27, Cow::Borrowed(Consumable::Trigger7.name())),
1025 (28, Cow::Borrowed(Consumable::Trigger8.name())),
1026 (29, Cow::Borrowed(Consumable::Trigger9.name())),
1027 (30, Cow::Borrowed(Consumable::Buff.name())),
1028 (31, Cow::Borrowed(Consumable::BuffsShift.name())),
1029 (32, Cow::Borrowed(Consumable::CircleWave.name())),
1030 (33, Cow::Borrowed(Consumable::GoDeep.name())),
1031 (34, Cow::Borrowed(Consumable::WeaponReloadBooster.name())),
1032 (35, Cow::Borrowed(Consumable::Hydrophone.name())),
1033 (36, Cow::Borrowed(Consumable::EnhancedRudders.name())),
1034 (37, Cow::Borrowed(Consumable::ReserveBattery.name())),
1035 (38, Cow::Borrowed(Consumable::GroupAuraBuff.name())),
1036 (39, Cow::Borrowed(Consumable::AffectedBuffAura.name())),
1037 (40, Cow::Borrowed(Consumable::InvisibilityExtraBuff.name())),
1038 (41, Cow::Borrowed(Consumable::SubmarineSurveillance.name())),
1039 (42, Cow::Borrowed(Consumable::PlaneSmokeGenerator.name())),
1040 (44, Cow::Borrowed(Consumable::Minefield.name())),
1041 (45, Cow::Borrowed(Consumable::TacticalTrigger1.name())),
1042 (46, Cow::Borrowed(Consumable::TacticalTrigger2.name())),
1043 (47, Cow::Borrowed(Consumable::TacticalTrigger3.name())),
1044 (48, Cow::Borrowed(Consumable::TacticalTrigger4.name())),
1045 (49, Cow::Borrowed(Consumable::TacticalTrigger5.name())),
1046 (50, Cow::Borrowed(Consumable::TacticalTrigger6.name())),
1047 (51, Cow::Borrowed(Consumable::ReconnaissanceSquad.name())),
1048 (52, Cow::Borrowed(Consumable::SmokePlane.name())),
1049 (53, Cow::Borrowed(Consumable::TacticalBuff.name())),
1050 (54, Cow::Borrowed(Consumable::PlaneTrigger1.name())),
1051 (55, Cow::Borrowed(Consumable::PlaneTrigger2.name())),
1052 (56, Cow::Borrowed(Consumable::PlaneTrigger3.name())),
1053 (57, Cow::Borrowed(Consumable::PlaneBuff.name())),
1054 (58, Cow::Borrowed(Consumable::Any.name())),
1055 (59, Cow::Borrowed(Consumable::All.name())),
1056 (60, Cow::Borrowed(Consumable::Special.name())),
1057 ]),
1058 battle_stages: HashMap::from([
1059 (0, crate::game_types::BattleStage::Waiting),
1060 (1, crate::game_types::BattleStage::Battle),
1061 (2, crate::game_types::BattleStage::Results),
1062 (3, crate::game_types::BattleStage::Finishing),
1063 (4, crate::game_types::BattleStage::Ended),
1064 ]),
1065 }
1066 }
1067
1068 pub fn plane_ammo_type(&self, id: i32) -> Option<&str> {
1069 self.plane_ammo_types.get(&id).map(|s| s.as_ref())
1070 }
1071
1072 pub fn torpedo_type(&self, id: i32) -> Option<&str> {
1073 self.torpedo_types.get(&id).map(|s| s.as_ref())
1074 }
1075
1076 pub fn consumable_type(&self, id: i32) -> Option<&str> {
1077 self.consumable_types.get(&id).map(|s| s.as_ref())
1078 }
1079
1080 pub fn plane_ammo_types(&self) -> &HashMap<i32, Cow<'static, str>> {
1081 &self.plane_ammo_types
1082 }
1083
1084 pub fn torpedo_types(&self) -> &HashMap<i32, Cow<'static, str>> {
1085 &self.torpedo_types
1086 }
1087
1088 pub fn consumable_types(&self) -> &HashMap<i32, Cow<'static, str>> {
1089 &self.consumable_types
1090 }
1091
1092 pub fn plane_ammo_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
1093 &mut self.plane_ammo_types
1094 }
1095
1096 pub fn torpedo_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
1097 &mut self.torpedo_types
1098 }
1099
1100 pub fn consumable_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
1101 &mut self.consumable_types
1102 }
1103
1104 pub fn battle_stage(&self, id: i32) -> Option<&crate::game_types::BattleStage> {
1105 self.battle_stages.get(&id)
1106 }
1107
1108 pub fn battle_stages(&self) -> &HashMap<i32, crate::game_types::BattleStage> {
1109 &self.battle_stages
1110 }
1111
1112 pub fn battle_stages_mut(&mut self) -> &mut HashMap<i32, crate::game_types::BattleStage> {
1113 &mut self.battle_stages
1114 }
1115}
1116
1117#[derive(Clone)]
1119pub struct ChannelConstants {
1120 battle_chat_channel_types: HashMap<i32, Cow<'static, str>>,
1121 channel_type_idents: HashMap<i32, Cow<'static, str>>,
1122}
1123
1124impl ChannelConstants {
1125 #[cfg(feature = "parsing")]
1128 pub fn from_xml(xml: &[u8]) -> Self {
1129 let xml_str = match std::str::from_utf8(xml) {
1130 Ok(s) => s,
1131 Err(_) => return Self::defaults(),
1132 };
1133
1134 let defaults = Self::defaults();
1135 Self {
1136 battle_chat_channel_types: parse_integer_enum(xml_str, "BATTLE_CHAT_CHANNEL_TYPE")
1137 .unwrap_or(defaults.battle_chat_channel_types),
1138 channel_type_idents: parse_positional_enum(xml_str, "CHANNEL_TYPE_IDENT_VALUE")
1139 .unwrap_or(defaults.channel_type_idents),
1140 }
1141 }
1142
1143 pub fn defaults() -> Self {
1145 Self {
1146 battle_chat_channel_types: HashMap::from([
1147 (0, Cow::Borrowed("GENERAL")),
1148 (1, Cow::Borrowed("TEAM")),
1149 (2, Cow::Borrowed("DIVISION")),
1150 (3, Cow::Borrowed("SYSTEM")),
1151 ]),
1152 channel_type_idents: HashMap::from([
1153 (0, Cow::Borrowed("UNKNOWN")),
1154 (1, Cow::Borrowed("GROUP_OPEN")),
1155 (2, Cow::Borrowed("GROUP_CLOSED")),
1156 (3, Cow::Borrowed("PREBATTLE")),
1157 (4, Cow::Borrowed("COMMON")),
1158 (5, Cow::Borrowed("PRIVATE")),
1159 (6, Cow::Borrowed("CLAN")),
1160 (7, Cow::Borrowed("TRAINING_ROOM")),
1161 ]),
1162 }
1163 }
1164
1165 pub fn battle_chat_channel_type(&self, id: i32) -> Option<&str> {
1166 self.battle_chat_channel_types.get(&id).map(|s| s.as_ref())
1167 }
1168
1169 pub fn channel_type_ident(&self, id: i32) -> Option<&str> {
1170 self.channel_type_idents.get(&id).map(|s| s.as_ref())
1171 }
1172
1173 pub fn battle_chat_channel_types(&self) -> &HashMap<i32, Cow<'static, str>> {
1174 &self.battle_chat_channel_types
1175 }
1176
1177 pub fn channel_type_idents(&self) -> &HashMap<i32, Cow<'static, str>> {
1178 &self.channel_type_idents
1179 }
1180
1181 pub fn battle_chat_channel_types_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
1182 &mut self.battle_chat_channel_types
1183 }
1184
1185 pub fn channel_type_idents_mut(&mut self) -> &mut HashMap<i32, Cow<'static, str>> {
1186 &mut self.channel_type_idents
1187 }
1188}
1189
1190#[cfg(feature = "parsing")]
1192fn parse_integer_enum(xml: &str, enum_name: &str) -> Option<HashMap<i32, Cow<'static, str>>> {
1193 let doc = roxmltree::Document::parse(xml).ok()?;
1194 let enum_node = doc.descendants().find(|n| n.has_tag_name("enum") && n.attribute("name") == Some(enum_name))?;
1195
1196 let mut map = HashMap::new();
1197 for child in enum_node.children() {
1198 if child.has_tag_name("const")
1199 && let (Some(name), Some(value_str)) = (child.attribute("name"), child.attribute("value"))
1200 && let Ok(value) = value_str.trim().parse::<i32>()
1201 {
1202 map.insert(value, Cow::Owned(name.to_string()));
1203 }
1204 }
1205
1206 if map.is_empty() { None } else { Some(map) }
1207}
1208
1209#[cfg(feature = "parsing")]
1211fn parse_positional_enum(xml: &str, enum_name: &str) -> Option<HashMap<i32, Cow<'static, str>>> {
1212 let doc = roxmltree::Document::parse(xml).ok()?;
1213 let enum_node = doc.descendants().find(|n| n.has_tag_name("enum") && n.attribute("name") == Some(enum_name))?;
1214
1215 let mut map = HashMap::new();
1216 let mut index = 0i32;
1217 for child in enum_node.children() {
1218 if child.has_tag_name("const") {
1219 if let Some(name) = child.attribute("name") {
1220 map.insert(index, Cow::Owned(name.to_string()));
1221 }
1222 index += 1;
1223 }
1224 }
1225
1226 if map.is_empty() { None } else { Some(map) }
1227}
1228
1229pub const BATTLE_CONSTANTS_PATH: &str = "gui/data/constants/battle.xml";
1231
1232pub const SHIPS_CONSTANTS_PATH: &str = "gui/data/constants/ships.xml";
1234
1235pub const WEAPONS_CONSTANTS_PATH: &str = "gui/data/constants/weapons.xml";
1237
1238pub const COMMON_CONSTANTS_PATH: &str = "gui/data/constants/common.xml";
1240
1241pub const CHANNEL_CONSTANTS_PATH: &str = "gui/data/constants/channel.xml";