|
- use std::cmp::min;
- use std::ops::{Index, IndexMut, Mul};
-
- use glc::vector::Vector2f;
- use serde::{Deserialize, Serialize};
- use specs::{Component, Entity, VecStorage};
-
- use crate::{builder::ShipBuilder, misc::FlaggedStorage};
-
- #[derive(Clone, Debug, Serialize, Deserialize)]
- pub struct Ship {
- type_: ShipType,
- dir: Vector2f,
-
- #[serde(skip)]
- obstacle: ShipObstacle,
-
- #[serde(skip)]
- target_pos: Vector2f,
-
- #[serde(skip)]
- target_dir: Vector2f,
- }
-
- #[derive(Copy, Clone, Debug, PartialEq, Eq)]
- pub enum ShipObstacle {
- Known(Entity),
- Search,
- Done,
- }
-
- #[derive(Copy, Clone, Debug, Default)]
- pub struct ShipCount {
- pub fighter: usize,
- pub bomber: usize,
- pub transporter: usize,
- }
-
- #[derive(Clone, Default, Debug)]
- pub struct ShipsData {
- pub fighter: ShipData,
- pub bomber: ShipData,
- pub transporter: ShipData,
- }
-
- #[derive(Clone, Default, Debug)]
- pub struct ShipData {
- pub speed: f32,
- }
-
- #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
- pub enum ShipType {
- Fighter,
- Bomber,
- Transporter,
- }
-
- /* Ship */
-
- impl Ship {
- #[inline]
- pub fn builder() -> ShipBuilder {
- ShipBuilder::default()
- }
-
- #[inline]
- pub fn type_(&self) -> ShipType {
- self.type_
- }
-
- #[inline]
- pub fn dir(&self) -> &Vector2f {
- &self.dir
- }
-
- #[inline]
- pub fn target_pos(&self) -> &Vector2f {
- &self.target_pos
- }
-
- #[inline]
- pub fn target_dir(&self) -> &Vector2f {
- &self.target_dir
- }
-
- #[inline]
- pub fn obstacle(&self) -> ShipObstacle {
- self.obstacle
- }
- }
-
- impl Ship {
- #[inline]
- pub(crate) fn new(type_: ShipType, dir: Vector2f) -> Self {
- Self {
- type_,
- dir,
- obstacle: Default::default(),
- target_pos: Default::default(),
- target_dir: Default::default(),
- }
- }
-
- #[inline]
- pub(crate) fn set_target(&mut self, pos: Vector2f, dir: Vector2f) {
- self.target_pos = pos;
- self.target_dir = dir;
- }
-
- #[inline]
- pub(crate) fn dir_mut(&mut self) -> &mut Vector2f {
- &mut self.dir
- }
-
- #[inline]
- pub(crate) fn obstacle_mut(&mut self) -> &mut ShipObstacle {
- &mut self.obstacle
- }
- }
-
- impl Component for Ship {
- type Storage = FlaggedStorage<Self, VecStorage<Self>>;
- }
-
- /* Obstacle */
-
- impl Default for ShipObstacle {
- fn default() -> Self {
- Self::Search
- }
- }
-
- /* Count */
-
- impl ShipCount {
- pub fn all() -> Self {
- Self {
- fighter: usize::MAX,
- bomber: usize::MAX,
- transporter: usize::MAX,
- }
- }
-
- pub fn none() -> Self {
- Self {
- fighter: 0,
- bomber: 0,
- transporter: 0,
- }
- }
-
- pub fn total(&self) -> usize {
- self.fighter
- .saturating_add(self.bomber)
- .saturating_add(self.transporter)
- }
-
- pub fn merge(&self, other: &Self) -> Self {
- Self {
- fighter: min(self.fighter, other.fighter),
- bomber: min(self.bomber, other.bomber),
- transporter: min(self.transporter, other.transporter),
- }
- }
-
- pub fn is_all(&self) -> bool {
- self.fighter == usize::MAX && self.bomber == usize::MAX && self.transporter == usize::MAX
- }
- }
-
- impl Index<usize> for ShipCount {
- type Output = usize;
-
- fn index(&self, index: usize) -> &Self::Output {
- match index {
- 0 => &self.fighter,
- 1 => &self.bomber,
- 2 => &self.transporter,
- x => panic!("Invalid ship count index: {}", x),
- }
- }
- }
-
- impl IndexMut<usize> for ShipCount {
- fn index_mut(&mut self, index: usize) -> &mut Self::Output {
- match index {
- 0 => &mut self.fighter,
- 1 => &mut self.bomber,
- 2 => &mut self.transporter,
- x => panic!("Invalid ship count index: {}", x),
- }
- }
- }
-
- impl Index<ShipType> for ShipCount {
- type Output = usize;
-
- fn index(&self, index: ShipType) -> &Self::Output {
- match index {
- ShipType::Fighter => &self.fighter,
- ShipType::Bomber => &self.bomber,
- ShipType::Transporter => &self.transporter,
- }
- }
- }
-
- impl IndexMut<ShipType> for ShipCount {
- fn index_mut(&mut self, index: ShipType) -> &mut Self::Output {
- match index {
- ShipType::Fighter => &mut self.fighter,
- ShipType::Bomber => &mut self.bomber,
- ShipType::Transporter => &mut self.transporter,
- }
- }
- }
-
- impl Mul<f32> for ShipCount {
- type Output = ShipCount;
-
- #[allow(unused_assignments)]
- fn mul(self, rhs: f32) -> Self::Output {
- let expected = self.total() as f32;
- let expected = (rhs * expected).ceil() as usize;
-
- let mut fighter = (rhs * self.fighter as f32) as usize;
- let mut bomber = (rhs * self.bomber as f32) as usize;
- let mut transporter = (rhs * self.transporter as f32) as usize;
-
- let mut actual = fighter.saturating_add(bomber).saturating_add(transporter);
-
- if actual < expected && fighter < self.fighter {
- fighter += 1;
- actual += 1;
- }
-
- if actual < expected && bomber < self.bomber {
- bomber += 1;
- actual += 1;
- }
-
- if actual < expected && transporter < self.transporter {
- transporter += 1;
- actual += 1;
- }
-
- ShipCount {
- fighter,
- bomber,
- transporter,
- }
- }
- }
-
- /* ShipsData */
-
- impl Index<usize> for ShipsData {
- type Output = ShipData;
-
- fn index(&self, index: usize) -> &Self::Output {
- match index {
- 0 => &self.fighter,
- 1 => &self.bomber,
- 2 => &self.transporter,
- x => panic!("Invalid ships data index: {}", x),
- }
- }
- }
-
- impl Index<ShipType> for ShipsData {
- type Output = ShipData;
-
- fn index(&self, index: ShipType) -> &Self::Output {
- match index {
- ShipType::Fighter => &self.fighter,
- ShipType::Bomber => &self.bomber,
- ShipType::Transporter => &self.transporter,
- }
- }
- }
|