diff --git a/content/guns.toml b/content/guns.toml index fba050a..30ecf15 100644 --- a/content/guns.toml +++ b/content/guns.toml @@ -1,5 +1,7 @@ [gun."blaster"] +space.weapon = 10 + # Angle of fire cone # Smaller angle = more accurate spread = 2 diff --git a/content/outfits.toml b/content/outfits.toml index d44b79a..69452bc 100644 --- a/content/outfits.toml +++ b/content/outfits.toml @@ -1,4 +1,7 @@ [outfit."plasma engines"] + +space.engine = 20 + engine.thrust = 100 engine.flare_texture = "flare::ion" steering.power = 20 diff --git a/content/ship.toml b/content/ship.toml index a68c534..0073436 100644 --- a/content/ship.toml +++ b/content/ship.toml @@ -6,6 +6,11 @@ hull = 200 linear_drag = 0.2 angular_drag = 0.2 + +space.outfit = 200 +space.engine = 50 +space.weapon = 50 + engines = [{ x = 0.0, y = -1.05, size = 50.0 }] guns = [{ x = 0.0, y = 1 }, { x = 0.1, y = 0.80 }, { x = -0.1, y = 0.80 }] diff --git a/crates/content/src/lib.rs b/crates/content/src/lib.rs index cb255ea..7c10a90 100644 --- a/crates/content/src/lib.rs +++ b/crates/content/src/lib.rs @@ -18,7 +18,9 @@ use toml; use walkdir::WalkDir; pub use handle::{FactionHandle, TextureHandle}; -pub use part::{EnginePoint, Faction, Gun, GunPoint, Outfit, Relationship, Ship, System, Texture}; +pub use part::{ + EnginePoint, Faction, Gun, GunPoint, Outfit, OutfitSpace, Relationship, Ship, System, Texture, +}; mod syntax { use anyhow::{bail, Result}; diff --git a/crates/content/src/part/gun.rs b/crates/content/src/part/gun.rs index 07a082b..72a0093 100644 --- a/crates/content/src/part/gun.rs +++ b/crates/content/src/part/gun.rs @@ -5,7 +5,10 @@ use cgmath::Deg; use crate::{handle::TextureHandle, Content}; +use super::OutfitSpace; + pub(crate) mod syntax { + use super::super::shared; use serde::Deserialize; // Raw serde syntax structs. // These are never seen by code outside this crate. @@ -16,6 +19,7 @@ pub(crate) mod syntax { pub spread: f32, pub rate: f32, pub rate_rng: f32, + pub space: shared::syntax::OutfitSpace, } #[derive(Debug, Deserialize)] @@ -53,6 +57,9 @@ pub struct Gun { /// Random variation of projectile delay, in seconds. /// Each shot waits (rate += rate_rng). pub rate_rng: f32, + + /// How much space this gun uses + pub space: OutfitSpace, } /// Represents a projectile that a [`Gun`] produces. @@ -98,6 +105,7 @@ impl crate::Build for Gun { ct.guns.push(Self { name: gun_name, + space: gun.space.into(), spread: Deg(gun.spread), rate: gun.rate, rate_rng: gun.rate_rng, diff --git a/crates/content/src/part/mod.rs b/crates/content/src/part/mod.rs index 62b35c9..3105ee8 100644 --- a/crates/content/src/part/mod.rs +++ b/crates/content/src/part/mod.rs @@ -3,6 +3,7 @@ pub mod faction; pub mod gun; pub mod outfit; +mod shared; pub mod ship; pub mod system; pub mod texture; @@ -10,6 +11,7 @@ pub mod texture; pub use faction::{Faction, Relationship}; pub use gun::{Gun, Projectile}; pub use outfit::Outfit; +pub use shared::OutfitSpace; pub use ship::{EnginePoint, GunPoint, Ship}; pub use system::{Object, System}; pub use texture::Texture; diff --git a/crates/content/src/part/outfit.rs b/crates/content/src/part/outfit.rs index bda600d..f1ddf60 100644 --- a/crates/content/src/part/outfit.rs +++ b/crates/content/src/part/outfit.rs @@ -4,7 +4,10 @@ use anyhow::{bail, Result}; use crate::{handle::TextureHandle, Content}; +use super::OutfitSpace; + pub(crate) mod syntax { + use super::super::shared; use serde::Deserialize; // Raw serde syntax structs. // These are never seen by code outside this crate. @@ -13,6 +16,7 @@ pub(crate) mod syntax { pub struct Outfit { pub engine: Option, pub steering: Option, + pub space: shared::syntax::OutfitSpace, } #[derive(Debug, Deserialize)] @@ -43,6 +47,9 @@ pub struct Outfit { /// Its location and size is determined by a ship's /// engine points. pub engine_flare_texture: Option, + + /// How much space this outfit requires + pub space: OutfitSpace, } impl crate::Build for Outfit { @@ -55,6 +62,7 @@ impl crate::Build for Outfit { engine_thrust: 0.0, steer_power: 0.0, engine_flare_texture: None, + space: OutfitSpace::from(outfit.space), }; // Engine stats diff --git a/crates/content/src/part/shared.rs b/crates/content/src/part/shared.rs new file mode 100644 index 0000000..70036eb --- /dev/null +++ b/crates/content/src/part/shared.rs @@ -0,0 +1,67 @@ +pub(crate) mod syntax { + use serde::Deserialize; + + #[derive(Debug, Deserialize)] + pub struct OutfitSpace { + pub outfit: Option, + pub weapon: Option, + pub engine: Option, + } +} + +/// Represents outfit space, either that available in a ship +/// or that used by an outfit. +#[derive(Debug, Clone, Copy)] +pub struct OutfitSpace { + /// Total available outfit space. + /// This should be greater than weapon and engine. + pub outfit: u32, + + /// Space for weapons + pub weapon: u32, + + /// Space for engine + pub engine: u32, +} + +impl OutfitSpace { + /// Make a new, zero OutfitSpace + pub fn new() -> Self { + Self { + outfit: 0, + weapon: 0, + engine: 0, + } + } + + /// Does this outfit contain `smaller`? + pub fn can_contain(&self, smaller: Self) -> bool { + self.outfit >= (smaller.outfit + smaller.weapon + smaller.engine) + && self.weapon >= smaller.weapon + && self.engine >= smaller.engine + } + + /// Free outfit space + pub fn free(&mut self, rhs: &Self) { + self.outfit += rhs.outfit + rhs.weapon + rhs.engine; + self.weapon += rhs.weapon; + self.engine += rhs.engine; + } + + /// Occupy outfit space + pub fn occupy(&mut self, rhs: &Self) { + self.outfit -= rhs.outfit + rhs.weapon + rhs.engine; + self.weapon -= rhs.weapon; + self.engine -= rhs.engine; + } +} + +impl From for OutfitSpace { + fn from(value: syntax::OutfitSpace) -> Self { + Self { + outfit: value.outfit.unwrap_or(0), + engine: value.engine.unwrap_or(0), + weapon: value.weapon.unwrap_or(0), + } + } +} diff --git a/crates/content/src/part/ship.rs b/crates/content/src/part/ship.rs index 8506a4a..2b95831 100644 --- a/crates/content/src/part/ship.rs +++ b/crates/content/src/part/ship.rs @@ -6,8 +6,12 @@ use nalgebra::{point, Point}; use crate::{handle::TextureHandle, Content}; +use super::OutfitSpace; + pub(crate) mod syntax { + use super::super::shared; use serde::Deserialize; + // Raw serde syntax structs. // These are never seen by code outside this crate. @@ -22,6 +26,7 @@ pub(crate) mod syntax { pub collision: Collision, pub angular_drag: f32, pub linear_drag: f32, + pub space: shared::syntax::OutfitSpace, } #[derive(Debug, Deserialize)] @@ -86,6 +91,9 @@ pub struct Ship { /// Reduction in velocity over time pub linear_drag: f32, + + /// Outfit space in this ship + pub space: OutfitSpace, } /// Collision shape for this ship @@ -138,6 +146,7 @@ impl crate::Build for Ship { name: ship_name, sprite_texture: th, mass: ship.mass, + space: OutfitSpace::from(ship.space), angular_drag: ship.angular_drag, linear_drag: ship.linear_drag, size, diff --git a/src/game/game.rs b/src/game/game.rs index 35f9a81..eda9485 100644 --- a/src/game/game.rs +++ b/src/game/game.rs @@ -53,7 +53,6 @@ impl Game { let mut o2 = outfits::ShipOutfits::new(&ct.ships[0]); o2.add(ct.outfits[0].clone()); o2.add_gun(ct.guns[0].clone()); - println!("{:?}", o2); let h3 = physics.add_ship( &ct.ships[0], o2, diff --git a/src/game/outfits.rs b/src/game/outfits.rs index 981a7d3..ff3283c 100644 --- a/src/game/outfits.rs +++ b/src/game/outfits.rs @@ -1,5 +1,5 @@ use cgmath::{Deg, Point3}; -use content::TextureHandle; +use content::{OutfitSpace, TextureHandle}; use crate::{content, render::SubSprite}; @@ -67,6 +67,9 @@ impl OutfitStatSum { #[derive(Debug)] pub struct ShipOutfits { pub stats: OutfitStatSum, + pub total_space: OutfitSpace, + + available_space: OutfitSpace, outfits: Vec, guns: Vec, enginepoints: Vec, @@ -83,16 +86,30 @@ impl<'a> ShipOutfits { stats: OutfitStatSum::new(), outfits: Vec::new(), guns: Vec::new(), + available_space: content.space.clone(), + total_space: content.space.clone(), enginepoints: content.engines.clone(), gunpoints: content.guns.clone(), engine_flare_sprites: vec![], } } + /// Does this outfit set contain the specified outfit? + pub fn contains_outfit(&self, o: &content::Outfit) -> bool { + match self.outfits.iter().position(|x| x.name == o.name) { + Some(_) => true, + None => false, + } + } + /// Add an outfit to this ship. /// Returns true on success, and false on failure /// TODO: failure reason enum pub fn add(&mut self, o: content::Outfit) -> bool { + if !self.available_space.can_contain(o.space) { + return false; + } + self.available_space.occupy(&o.space); self.stats.add(&o); self.outfits.push(o); self.update_engine_flares(); @@ -100,10 +117,13 @@ impl<'a> ShipOutfits { } /// TODO: is outfit in set? - /// TODO: don't remove nonexisting outfit pub fn remove(&mut self, o: content::Outfit) { - self.outfits - .remove(self.outfits.iter().position(|x| x.name == o.name).unwrap()); + let i = match self.outfits.iter().position(|x| x.name == o.name) { + Some(i) => i, + None => panic!("Removed non-existing outfit"), + }; + self.available_space.free(&o.space); + self.outfits.remove(i); self.stats.remove(&o); self.update_engine_flares(); }