Galactica/crates/gameobject/src/ship/outfitset.rs

188 lines
4.8 KiB
Rust
Raw Normal View History

2024-01-08 22:38:36 -08:00
use std::collections::HashMap;
use content::{GunPoint, OutfitHandle, OutfitSpace};
use galactica_content as content;
/// Possible outcomes when adding an outfit
pub enum OutfitAddResult {
/// An outfit was successfully added
Ok,
/// An outfit could not be added because we don't have enough free space.
/// The string tells us what kind of space we need:
/// `outfit,` `weapon,` `engine,` etc. Note that these sometimes overlap:
/// outfits may need outfit AND weapon space. In these cases, this result
/// should name the "most specific" kind of space we lack.
NotEnoughSpace(String),
}
/// Possible outcomes when removing an outfit
pub enum OutfitRemoveResult {
/// This outfit was successfully removed
Ok,
/// This outfit isn't in this set
NotExist,
// TODO:
// This is where we'll add non-removable outfits,
// outfits that provide space, etc
}
/// A simple data class, used to keep track of delayed shield generators
#[derive(Debug)]
pub(crate) struct ShieldGenerator {
pub outfit: OutfitHandle,
pub delay: f32,
pub generation: f32,
}
/// This struct keeps track of a ship's outfit loadout.
#[derive(Debug)]
pub struct OutfitSet {
/// What outfits does this statsum contain?
outfits: HashMap<OutfitHandle, u32>,
/// Space available in this outfitset.
/// set at creation and never changes.
total_space: OutfitSpace,
/// Space used by the outfits in this set.
/// This may be negative if certain outfits provide space!
used_space: OutfitSpace,
/// The gun points available in this ship.
/// If value is None, this point is free.
/// if value is Some, this point is taken.
gun_points: HashMap<GunPoint, Option<OutfitHandle>>,
// Outfit values
// This isn't strictly necessary, but we don't want to
// re-compute this on each frame.
engine_thrust: f32,
steer_power: f32,
shield_strength: f32,
// Delay, generation
// TODO: struct
shield_generators: Vec<ShieldGenerator>,
}
impl OutfitSet {
pub fn new(available_space: OutfitSpace, gun_points: &[GunPoint]) -> Self {
Self {
outfits: HashMap::new(),
total_space: available_space,
used_space: OutfitSpace::new(),
gun_points: gun_points.iter().map(|x| (x.clone(), None)).collect(),
engine_thrust: 0.0,
steer_power: 0.0,
shield_strength: 0.0,
shield_generators: Vec::new(),
}
}
pub fn add(&mut self, o: &content::Outfit) -> OutfitAddResult {
if !(self.total_space - self.used_space).can_contain(&o.space) {
return OutfitAddResult::NotEnoughSpace("TODO".to_string());
}
self.used_space += o.space;
self.engine_thrust += o.engine_thrust;
self.steer_power += o.steer_power;
self.shield_strength += o.shield_strength;
self.shield_generators.push(ShieldGenerator {
outfit: o.handle,
delay: o.shield_delay,
generation: o.shield_generation,
});
return OutfitAddResult::Ok;
}
pub fn remove(&mut self, o: &content::Outfit) -> OutfitRemoveResult {
if !self.outfits.contains_key(&o.handle) {
return OutfitRemoveResult::NotExist;
} else {
let n = *self.outfits.get(&o.handle).unwrap();
if n == 1u32 {
self.outfits.remove(&o.handle);
} else {
*self.outfits.get_mut(&o.handle).unwrap() -= 1;
}
}
self.used_space -= o.space;
self.engine_thrust -= o.engine_thrust;
self.steer_power -= o.steer_power;
self.shield_strength -= o.shield_strength;
{
// This index will exist, since we checked the hashmap
let index = self
.shield_generators
.iter()
.position(|g| g.outfit == o.handle)
.unwrap();
self.shield_generators.remove(index);
}
return OutfitRemoveResult::Ok;
}
}
// Simple getters to make sure nobody meddles with our internal state
impl OutfitSet {
/// The number of outfits in this set
pub fn len(&self) -> u32 {
self.outfits.iter().map(|(_, x)| x).sum()
}
/// Iterate over all outfits
pub fn iter_outfits(&self) -> impl Iterator<Item = (&OutfitHandle, &u32)> {
self.outfits.iter()
}
/// Iterate over all gun points
pub fn iter_gun_points(&self) -> impl Iterator<Item = (&GunPoint, &Option<OutfitHandle>)> {
self.gun_points.iter()
}
/// Iterate over all shield generators
pub(crate) fn iter_shield_generators(&self) -> impl Iterator<Item = &ShieldGenerator> {
self.shield_generators.iter()
}
/// Get maximum possible shield regen
pub fn get_max_shield_regen(&self) -> f32 {
self.shield_generators.iter().map(|x| x.generation).sum()
}
/// Total available outfit space
pub fn get_total_space(&self) -> &OutfitSpace {
&self.total_space
}
/// Used outfit space
pub fn get_used_space(&self) -> &OutfitSpace {
&self.used_space
}
/// Total foward thrust
pub fn get_engine_thrust(&self) -> f32 {
self.engine_thrust
}
/// Total steer power
pub fn get_steer_power(&self) -> f32 {
self.steer_power
}
/// Total shield strength
pub fn get_shield_strength(&self) -> f32 {
self.shield_strength
}
}