178 lines
4.0 KiB
Rust
Raw Normal View History

2024-01-09 17:23:54 -08:00
use std::{collections::HashMap, time::Instant};
2024-01-08 22:38:36 -08:00
2024-01-09 11:34:54 -08:00
use crate::GameShipHandle;
2024-01-08 23:05:07 -08:00
use super::{OutfitSet, ShipPersonality};
2024-01-09 17:23:54 -08:00
use content::GunPoint;
2024-01-08 22:38:36 -08:00
use galactica_content as content;
2024-01-09 17:23:54 -08:00
use rand::{rngs::ThreadRng, Rng};
2024-01-08 22:38:36 -08:00
#[derive(Debug)]
pub struct Ship {
// Metadata values
2024-01-09 11:34:54 -08:00
handle: GameShipHandle,
2024-01-08 23:05:07 -08:00
ct_handle: content::ShipHandle,
faction: content::FactionHandle,
outfits: OutfitSet,
personality: ShipPersonality,
2024-01-08 22:38:36 -08:00
// State values
2024-01-08 23:05:07 -08:00
// TODO: unified ship stats struct, like outfit space
hull: f32,
shields: f32,
2024-01-09 17:23:54 -08:00
gun_cooldowns: HashMap<GunPoint, f32>,
rng: ThreadRng,
2024-01-08 22:38:36 -08:00
// Utility values
/// The last time this ship was damaged
2024-01-08 23:05:07 -08:00
last_hit: Instant,
2024-01-08 22:38:36 -08:00
}
impl Ship {
2024-01-08 23:05:07 -08:00
pub(crate) fn new(
2024-01-08 22:38:36 -08:00
ct: &content::Content,
2024-01-09 11:34:54 -08:00
handle: GameShipHandle,
2024-01-08 22:38:36 -08:00
ct_handle: content::ShipHandle,
faction: content::FactionHandle,
2024-01-08 23:05:07 -08:00
personality: ShipPersonality,
2024-01-08 22:38:36 -08:00
) -> Self {
let s = ct.get_ship(ct_handle);
Ship {
2024-01-09 11:34:54 -08:00
handle,
2024-01-08 22:38:36 -08:00
ct_handle,
faction,
2024-01-09 17:23:54 -08:00
outfits: OutfitSet::new(s.space, &s.guns),
2024-01-08 23:05:07 -08:00
personality,
2024-01-08 22:38:36 -08:00
last_hit: Instant::now(),
2024-01-09 17:23:54 -08:00
rng: rand::thread_rng(),
2024-01-08 22:38:36 -08:00
// Initial stats
hull: s.hull,
2024-01-09 17:23:54 -08:00
shields: 0.0,
gun_cooldowns: s.guns.iter().map(|x| (x.clone(), 0.0)).collect(),
2024-01-08 22:38:36 -08:00
}
}
2024-01-09 17:23:54 -08:00
/// Add an outfit to this ship
pub fn add_outfit(&mut self, o: &content::Outfit) -> super::OutfitAddResult {
self.outfits.add(o)
}
/// Remove an outfit from this ship
pub fn remove_outfit(&mut self, o: &content::Outfit) -> super::OutfitRemoveResult {
self.outfits.remove(o)
}
2024-01-08 22:38:36 -08:00
/// If this ship is dead, it will be removed from the game.
pub fn is_dead(&self) -> bool {
self.hull <= 0.0
}
2024-01-09 17:23:54 -08:00
/// Try to fire a gun.
/// Will panic if `which` isn't a point on this ship.
/// Returns `true` if this gun was fired,
/// and `false` if it is on cooldown or empty.
pub fn fire_gun(&mut self, ct: &content::Content, which: &GunPoint) -> bool {
let c = self.gun_cooldowns.get_mut(which).unwrap();
if *c > 0.0 {
return false;
}
let g = self.outfits.get_gun(which);
if g.is_some() {
let g = ct.get_outfit(g.unwrap());
let gun = g.gun.as_ref().unwrap();
*c = 0f32.max(gun.rate + self.rng.gen_range(-gun.rate_rng..=gun.rate_rng));
return true;
} else {
return false;
}
}
2024-01-08 22:38:36 -08:00
/// Hit this ship with the given amount of damage
pub fn apply_damage(&mut self, mut d: f32) {
if self.is_dead() {
return;
}
if self.shields >= d {
self.shields -= d
} else {
d -= self.shields;
self.shields = 0.0;
self.hull = 0f32.max(self.hull - d);
}
self.last_hit = Instant::now();
}
/// Update this ship's state by `t` seconds
pub fn step(&mut self, t: f32) {
2024-01-09 17:23:54 -08:00
// Cooldown guns
for (_, c) in &mut self.gun_cooldowns {
if *c > 0.0 {
*c -= t;
}
}
// Regenerate shields
2024-01-08 22:38:36 -08:00
let time_since = self.last_hit.elapsed().as_secs_f32();
if self.shields != self.outfits.get_shield_strength() {
for g in self.outfits.iter_shield_generators() {
if time_since >= g.delay {
self.shields += g.generation * t;
if self.shields > self.outfits.get_shield_strength() {
self.shields = self.outfits.get_shield_strength();
break;
}
}
}
}
}
}
2024-01-08 23:05:07 -08:00
// Misc getters, so internal state is untouchable
impl Ship {
2024-01-09 11:34:54 -08:00
/// Get a handle to this ship game object
pub fn get_handle(&self) -> GameShipHandle {
self.handle
}
/// Get a handle to this ship's content
pub fn get_content(&self) -> content::ShipHandle {
self.ct_handle
}
2024-01-08 23:05:07 -08:00
/// Get this ship's current hull.
/// Use content handle to get maximum hull
pub fn get_hull(&self) -> f32 {
2024-01-09 11:34:54 -08:00
self.hull
2024-01-08 23:05:07 -08:00
}
/// Get this ship's current shields.
/// Use get_outfits() for maximum shields
pub fn get_shields(&self) -> f32 {
self.shields
}
/// Get all outfits on this ship
pub fn get_outfits(&self) -> &OutfitSet {
&self.outfits
}
/// Get this ship's personality
pub fn get_personality(&self) -> ShipPersonality {
self.personality
}
/// Get this ship's faction
pub fn get_faction(&self) -> content::FactionHandle {
self.faction
}
/// Get this ship's content handle
pub fn get_ship(&self) -> content::ShipHandle {
self.ct_handle
}
}