188 lines
4.8 KiB
Rust
188 lines
4.8 KiB
Rust
use content::{EnginePoint, SpriteHandle};
|
|
use galactica_content as content;
|
|
|
|
/// Represents a gun attached to a specific ship at a certain gunpoint.
|
|
#[derive(Debug)]
|
|
pub struct ShipGun {
|
|
/// The kind of gun this is
|
|
pub kind: content::Gun,
|
|
|
|
/// How many seconds we must wait before this gun can fire
|
|
pub cooldown: f32,
|
|
|
|
/// Index of the gunpoint this gun is attached to
|
|
pub point: usize,
|
|
}
|
|
|
|
impl ShipGun {
|
|
/// Make a new shipgun
|
|
pub fn new(kind: &content::Gun, point: usize) -> Self {
|
|
Self {
|
|
kind: kind.clone(),
|
|
point,
|
|
cooldown: 0.0,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// This struct keeps track of the combined stats of a set of outfits.
|
|
/// It does NOT check for sanity (e.g, removing an outfit that was never added)
|
|
/// That is handled by ShipOutfits.
|
|
#[derive(Debug)]
|
|
pub struct OutfitStatSum {
|
|
pub engine_thrust: f32,
|
|
pub steer_power: f32,
|
|
pub engine_flare_sprites: Vec<content::SpriteHandle>,
|
|
}
|
|
|
|
impl OutfitStatSum {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
engine_thrust: 0.0,
|
|
steer_power: 0.0,
|
|
engine_flare_sprites: Vec::new(),
|
|
}
|
|
}
|
|
|
|
pub fn add(&mut self, o: &content::Outfit) {
|
|
self.engine_thrust += o.engine_thrust;
|
|
if let Some(t) = o.engine_flare_sprite {
|
|
self.engine_flare_sprites.push(t);
|
|
};
|
|
self.steer_power += o.steer_power;
|
|
}
|
|
|
|
pub fn remove(&mut self, o: &content::Outfit) {
|
|
self.engine_thrust -= o.engine_thrust;
|
|
if let Some(t) = o.engine_flare_sprite {
|
|
self.engine_flare_sprites.remove(
|
|
self.engine_flare_sprites
|
|
.iter()
|
|
.position(|x| *x == t)
|
|
.unwrap(),
|
|
);
|
|
}
|
|
self.steer_power -= o.steer_power;
|
|
}
|
|
}
|
|
|
|
/// Represents a set of outfits attached to a ship.
|
|
/// Keeps track of the sum of their stats, so it mustn't be re-computed every frame.
|
|
#[derive(Debug)]
|
|
pub struct OutfitSet {
|
|
/// The total sum of the stats this set of outfits provides
|
|
stats: OutfitStatSum,
|
|
|
|
//pub total_space: content::OutfitSpace,
|
|
available_space: content::OutfitSpace,
|
|
outfits: Vec<content::OutfitHandle>,
|
|
guns: Vec<ShipGun>,
|
|
enginepoints: Vec<content::EnginePoint>,
|
|
gunpoints: Vec<content::GunPoint>,
|
|
}
|
|
|
|
impl<'a> OutfitSet {
|
|
/// Make a new outfit array
|
|
pub fn new(content: &content::Ship) -> Self {
|
|
Self {
|
|
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(),
|
|
}
|
|
}
|
|
|
|
/// Does this outfit set contain the specified outfit?
|
|
pub fn contains_outfit(&self, o: content::OutfitHandle) -> bool {
|
|
match self.outfits.iter().position(|x| *x == o) {
|
|
Some(_) => true,
|
|
None => false,
|
|
}
|
|
}
|
|
|
|
pub fn stat_sum(&self) -> &OutfitStatSum {
|
|
&self.stats
|
|
}
|
|
|
|
/// Add an outfit to this ship.
|
|
/// Returns true on success, and false on failure
|
|
/// TODO: failure reason enum
|
|
pub fn add(&mut self, ct: &content::Content, o: content::OutfitHandle) -> bool {
|
|
let outfit = ct.get_outfit(o);
|
|
if !self.available_space.can_contain(&outfit.space) {
|
|
return false;
|
|
}
|
|
self.available_space.occupy(&outfit.space);
|
|
self.stats.add(&outfit);
|
|
self.outfits.push(o);
|
|
//self.update_engine_flares();
|
|
return true;
|
|
}
|
|
|
|
/// Remove an outfit from this set
|
|
pub fn remove(&mut self, ct: &content::Content, o: content::OutfitHandle) {
|
|
let outfit = ct.get_outfit(o);
|
|
let i = match self.outfits.iter().position(|x| *x == o) {
|
|
Some(i) => i,
|
|
None => panic!("removed non-existing outfit"),
|
|
};
|
|
self.available_space.free(&outfit.space);
|
|
self.outfits.remove(i);
|
|
self.stats.remove(&outfit);
|
|
//self.update_engine_flares();
|
|
}
|
|
|
|
/// Add a gun to this outfit set.
|
|
/// This automatically attaches the gun to the first available gunpoint,
|
|
/// and returns false (applying no changes) if no points are available.
|
|
pub fn add_gun(&mut self, ct: &content::Content, g: content::GunHandle) -> bool {
|
|
// Find first unused point
|
|
let mut p = None;
|
|
'outer: for i in 0..self.gunpoints.len() {
|
|
for g in &self.guns {
|
|
if g.point == i {
|
|
continue 'outer;
|
|
}
|
|
}
|
|
p = Some(i);
|
|
break;
|
|
}
|
|
let gun = ct.get_gun(g);
|
|
|
|
// All points are taken
|
|
if p.is_none() {
|
|
return false;
|
|
}
|
|
|
|
let sg = ShipGun::new(gun, p.unwrap());
|
|
self.guns.push(sg);
|
|
return true;
|
|
}
|
|
|
|
/// Iterate over all guns in this outfitset
|
|
pub fn iter_guns(&mut self) -> impl Iterator<Item = &mut ShipGun> {
|
|
self.guns.iter_mut()
|
|
}
|
|
|
|
/// Iterate over all guns and the gunpoints they're attached to
|
|
pub fn iter_guns_points(&mut self) -> impl Iterator<Item = (&mut ShipGun, &content::GunPoint)> {
|
|
self.guns
|
|
.iter_mut()
|
|
.map(|x| (&self.gunpoints[x.point], x))
|
|
.map(|(a, b)| (b, a))
|
|
}
|
|
|
|
// TODO: move to ship
|
|
/// Iterate over all ships in this physics system
|
|
pub fn iter_enginepoints(&self) -> impl Iterator<Item = &EnginePoint> + '_ {
|
|
self.enginepoints.iter()
|
|
}
|
|
|
|
pub fn get_flare_sprite(&self) -> Option<SpriteHandle> {
|
|
self.stats.engine_flare_sprites.iter().next().map(|x| *x)
|
|
}
|
|
}
|