use crate::game_params::types::Km;
use crate::game_params::types::Meters;
use crate::game_params::types::Millimeters;
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
pub struct Knots(f32);
impl Knots {
pub fn value(&self) -> f32 {
self.0
}
}
impl From<f32> for Knots {
fn from(v: f32) -> Self {
Self(v)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
pub struct Seconds(f32);
impl Seconds {
pub fn value(&self) -> f32 {
self.0
}
}
impl From<f32> for Seconds {
fn from(v: f32) -> Self {
Self(v)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
pub struct Hp(f32);
impl Hp {
pub fn value(&self) -> f32 {
self.0
}
}
impl From<f32> for Hp {
fn from(v: f32) -> Self {
Self(v)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
pub struct Percent(f32);
impl Percent {
pub fn value(&self) -> f32 {
self.0
}
}
impl From<f32> for Percent {
fn from(v: f32) -> Self {
Self(v)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
pub struct DegreesPerSecond(f32);
impl DegreesPerSecond {
pub fn value(&self) -> f32 {
self.0
}
}
impl From<f32> for DegreesPerSecond {
fn from(v: f32) -> Self {
Self(v)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
pub enum AmmoCount {
Finite(u32),
Infinite,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ShipStats {
pub durability: Option<Durability>,
pub mobility: Option<Mobility>,
pub armor: Option<Armor>,
pub battery: Option<Battery>,
pub artillery: Option<Artillery>,
pub secondaries: Option<Artillery>,
pub torpedoes: Option<Torpedoes>,
pub fire_control: Option<FireControl>,
pub visibility: Option<Visibility>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Durability {
pub health: Option<Hp>,
pub torpedo_protection: Option<Percent>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Mobility {
pub speed: Option<Knots>,
pub turning_radius: Option<Meters>,
pub rudder_time: Option<Seconds>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Armor {
pub min: Option<Millimeters>,
pub max: Option<Millimeters>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Battery {
pub capacity: Option<f32>,
pub regeneration: Option<f32>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MainGun {
pub caliber: Option<Millimeters>,
pub num_barrels: Option<u32>,
pub num_guns: Option<u32>,
pub rotation_speed: Option<DegreesPerSecond>,
pub rotation_time: Option<Seconds>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ShellStats {
pub name: String,
pub ammo_kind: Option<String>,
pub damage: Option<Hp>,
pub caliber: Option<Millimeters>,
pub speed: Option<f32>,
pub penetration: Option<Millimeters>,
pub burn_chance: Option<Percent>,
pub flood_chance: Option<Percent>,
pub max_ammo: Option<AmmoCount>,
pub disabled_underwater: Option<bool>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Artillery {
pub reload_time: Option<Seconds>,
pub range: Option<Km>,
pub dispersion: Option<Meters>,
pub ammo_switch_time: Option<Seconds>,
pub gun: Option<MainGun>,
pub shells: Vec<ShellStats>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Torpedoes {
pub reload_time: Option<Seconds>,
pub launchers: Vec<Launcher>,
pub torpedoes: Vec<TorpedoStats>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Launcher {
pub rotation_speed: Option<DegreesPerSecond>,
pub rotation_time: Option<Seconds>,
pub num_barrels: Option<u32>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TorpedoStats {
pub name: String,
pub damage: Option<Hp>,
pub speed: Option<Knots>,
pub range: Option<Km>,
pub visibility: Option<Km>,
pub distance_of_max_damage: Option<Km>,
pub is_damage_increasing: Option<bool>,
pub disabled_underwater: Option<bool>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FireControl {
pub max_dist: Option<Km>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Visibility {
pub sea_detection: Option<Km>,
pub sea_detection_on_fire: Option<Km>,
pub air_detection: Option<Km>,
pub air_detection_on_fire: Option<Km>,
pub detection_in_smoke: Option<Km>,
pub secondary_range_detection: Option<Km>,
pub periscope_depth_detection: Option<Km>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ship_stats_default_is_empty() {
let stats = ShipStats::default();
assert!(stats.durability.is_none());
assert!(stats.mobility.is_none());
assert!(stats.armor.is_none());
assert!(stats.battery.is_none());
assert!(stats.artillery.is_none());
assert!(stats.secondaries.is_none());
assert!(stats.torpedoes.is_none());
assert!(stats.fire_control.is_none());
assert!(stats.visibility.is_none());
}
#[test]
fn leaf_defaults_are_absent() {
let durability = Durability::default();
assert!(durability.health.is_none());
assert!(durability.torpedo_protection.is_none());
let mobility = Mobility::default();
assert!(mobility.speed.is_none());
assert!(mobility.turning_radius.is_none());
assert!(mobility.rudder_time.is_none());
}
#[test]
fn ammo_count_models_unlimited_pool() {
assert_eq!(AmmoCount::Finite(40), AmmoCount::Finite(40));
assert_ne!(AmmoCount::Finite(40), AmmoCount::Infinite);
}
}