use std::collections::HashMap; use anyhow::{bail, Result}; use cgmath::Deg; use crate::{Content, TextureHandle}; pub(super) mod syntax { use serde::Deserialize; // Raw serde syntax structs. // These are never seen by code outside this crate. #[derive(Debug, Deserialize)] pub struct Gun { pub projectile: Projectile, pub spread: f32, pub rate: f32, pub rate_rng: f32, } #[derive(Debug, Deserialize)] pub struct Projectile { pub sprite_texture: String, pub size: f32, pub size_rng: f32, pub speed: f32, pub speed_rng: f32, pub lifetime: f32, pub lifetime_rng: f32, pub damage: f32, } } /// Represents a gun outfit. #[derive(Debug, Clone)] pub struct Gun { /// The name of this gun pub name: String, /// The projectile this gun produces pub projectile: Projectile, /// The accuracy of this gun. /// Projectiles can be off center up to /// `spread / 2` degrees in both directions. /// /// (Forming a "fire cone" of `spread` degrees) pub spread: Deg, /// Average delay between projectiles, in seconds. pub rate: f32, /// Random variation of projectile delay, in seconds. /// Each shot waits (rate += rate_rng). pub rate_rng: f32, } /// Represents a projectile that a [`Gun`] produces. #[derive(Debug, Clone)] pub struct Projectile { /// The projectile sprite pub sprite_texture: TextureHandle, /// The average size of this projectile /// (height in game units) pub size: f32, /// Random size variation pub size_rng: f32, /// The speed of this projectile, in game units / second pub speed: f32, /// Random speed variation pub speed_rng: f32, /// The lifespan of this projectile. /// It will vanish if it lives this long without hitting anything. pub lifetime: f32, /// Random lifetime variation pub lifetime_rng: f32, /// The damage this projectile does pub damage: f32, } impl super::Build for Gun { type InputSyntax = HashMap; fn build(gun: Self::InputSyntax, ct: &mut Content) -> Result<()> { for (gun_name, gun) in gun { let th = match ct.texture_index.get(&gun.projectile.sprite_texture) { None => bail!( "In gun `{}`: texture `{}` doesn't exist", gun_name, gun.projectile.sprite_texture ), Some(t) => *t, }; ct.guns.push(Self { name: gun_name, spread: Deg(gun.spread), rate: gun.rate, rate_rng: gun.rate_rng, projectile: Projectile { sprite_texture: th, size: gun.projectile.size, size_rng: gun.projectile.size_rng, speed: gun.projectile.speed, speed_rng: gun.projectile.speed_rng, lifetime: gun.projectile.lifetime, lifetime_rng: gun.projectile.lifetime_rng, damage: gun.projectile.damage, }, }); } return Ok(()); } }