You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
6.6 KiB

  1. use std::cmp::min;
  2. use std::ops::{Index, IndexMut, Mul};
  3. use glc::vector::{Angle, Vector2f};
  4. use serde::{Deserialize, Serialize};
  5. use specs::{Component, Entity, VecStorage};
  6. use crate::{builder::ShipBuilder, misc::FlaggedStorage};
  7. #[derive(Clone, Debug, Serialize, Deserialize)]
  8. pub struct Ship {
  9. type_: ShipType,
  10. dir: Vector2f,
  11. }
  12. #[derive(Clone, Debug, Serialize, Deserialize)]
  13. pub struct ShipMoving {
  14. #[serde(skip)]
  15. obstacle: ShipObstacle,
  16. }
  17. #[derive(Clone, Debug, Serialize, Deserialize)]
  18. pub struct ShipOrbiting {
  19. #[serde(skip)]
  20. target_pos: Vector2f,
  21. #[serde(skip)]
  22. target_dir: Vector2f,
  23. }
  24. #[derive(Copy, Clone, Debug, PartialEq, Eq)]
  25. pub enum ShipObstacle {
  26. Known(Entity),
  27. Search,
  28. Done,
  29. }
  30. #[derive(Copy, Clone, Debug, Default)]
  31. pub struct ShipCount {
  32. pub fighter: usize,
  33. pub bomber: usize,
  34. pub transporter: usize,
  35. }
  36. #[derive(Clone, Default, Debug)]
  37. pub struct ShipsData {
  38. pub fighter: ShipData,
  39. pub bomber: ShipData,
  40. pub transporter: ShipData,
  41. }
  42. #[derive(Clone, Default, Debug)]
  43. pub struct ShipData {
  44. pub speed: f32,
  45. pub agility: Angle<f32>,
  46. }
  47. #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
  48. pub enum ShipType {
  49. Fighter,
  50. Bomber,
  51. Transporter,
  52. }
  53. /* Ship */
  54. impl Ship {
  55. #[inline]
  56. pub fn builder() -> ShipBuilder {
  57. ShipBuilder::default()
  58. }
  59. #[inline]
  60. pub fn type_(&self) -> ShipType {
  61. self.type_
  62. }
  63. #[inline]
  64. pub fn dir(&self) -> &Vector2f {
  65. &self.dir
  66. }
  67. }
  68. impl Ship {
  69. #[inline]
  70. pub(crate) fn new(type_: ShipType, dir: Vector2f) -> Self {
  71. Self { type_, dir }
  72. }
  73. #[inline]
  74. pub(crate) fn dir_mut(&mut self) -> &mut Vector2f {
  75. &mut self.dir
  76. }
  77. }
  78. impl Component for Ship {
  79. type Storage = FlaggedStorage<Self, VecStorage<Self>>;
  80. }
  81. /* ShipMoving */
  82. impl ShipMoving {
  83. pub fn obstacle(&self) -> &ShipObstacle {
  84. &self.obstacle
  85. }
  86. }
  87. impl ShipMoving {
  88. #[inline]
  89. pub(crate) fn new() -> Self {
  90. Self {
  91. obstacle: ShipObstacle::Search,
  92. }
  93. }
  94. pub(crate) fn obstacle_mut(&mut self) -> &mut ShipObstacle {
  95. &mut self.obstacle
  96. }
  97. }
  98. impl Component for ShipMoving {
  99. type Storage = VecStorage<Self>;
  100. }
  101. /* ShipOrbiting */
  102. impl ShipOrbiting {
  103. pub fn target_pos(&self) -> &Vector2f {
  104. &self.target_pos
  105. }
  106. pub fn target_dir(&self) -> &Vector2f {
  107. &self.target_dir
  108. }
  109. }
  110. impl ShipOrbiting {
  111. #[inline]
  112. pub(crate) fn new() -> Self {
  113. Self {
  114. target_pos: Default::default(),
  115. target_dir: Default::default(),
  116. }
  117. }
  118. #[inline]
  119. pub(crate) fn set_target(&mut self, pos: Vector2f, dir: Vector2f) {
  120. self.target_pos = pos;
  121. self.target_dir = dir;
  122. }
  123. }
  124. impl Component for ShipOrbiting {
  125. type Storage = VecStorage<Self>;
  126. }
  127. /* Obstacle */
  128. impl Default for ShipObstacle {
  129. fn default() -> Self {
  130. Self::Search
  131. }
  132. }
  133. /* Count */
  134. impl ShipCount {
  135. pub fn all() -> Self {
  136. Self {
  137. fighter: usize::MAX,
  138. bomber: usize::MAX,
  139. transporter: usize::MAX,
  140. }
  141. }
  142. pub fn none() -> Self {
  143. Self {
  144. fighter: 0,
  145. bomber: 0,
  146. transporter: 0,
  147. }
  148. }
  149. pub fn total(&self) -> usize {
  150. self.fighter
  151. .saturating_add(self.bomber)
  152. .saturating_add(self.transporter)
  153. }
  154. pub fn merge(&self, other: &Self) -> Self {
  155. Self {
  156. fighter: min(self.fighter, other.fighter),
  157. bomber: min(self.bomber, other.bomber),
  158. transporter: min(self.transporter, other.transporter),
  159. }
  160. }
  161. pub fn is_all(&self) -> bool {
  162. self.fighter == usize::MAX && self.bomber == usize::MAX && self.transporter == usize::MAX
  163. }
  164. }
  165. impl Index<usize> for ShipCount {
  166. type Output = usize;
  167. fn index(&self, index: usize) -> &Self::Output {
  168. match index {
  169. 0 => &self.fighter,
  170. 1 => &self.bomber,
  171. 2 => &self.transporter,
  172. x => panic!("Invalid ship count index: {}", x),
  173. }
  174. }
  175. }
  176. impl IndexMut<usize> for ShipCount {
  177. fn index_mut(&mut self, index: usize) -> &mut Self::Output {
  178. match index {
  179. 0 => &mut self.fighter,
  180. 1 => &mut self.bomber,
  181. 2 => &mut self.transporter,
  182. x => panic!("Invalid ship count index: {}", x),
  183. }
  184. }
  185. }
  186. impl Index<ShipType> for ShipCount {
  187. type Output = usize;
  188. fn index(&self, index: ShipType) -> &Self::Output {
  189. match index {
  190. ShipType::Fighter => &self.fighter,
  191. ShipType::Bomber => &self.bomber,
  192. ShipType::Transporter => &self.transporter,
  193. }
  194. }
  195. }
  196. impl IndexMut<ShipType> for ShipCount {
  197. fn index_mut(&mut self, index: ShipType) -> &mut Self::Output {
  198. match index {
  199. ShipType::Fighter => &mut self.fighter,
  200. ShipType::Bomber => &mut self.bomber,
  201. ShipType::Transporter => &mut self.transporter,
  202. }
  203. }
  204. }
  205. impl Mul<f32> for ShipCount {
  206. type Output = ShipCount;
  207. #[allow(unused_assignments)]
  208. fn mul(self, rhs: f32) -> Self::Output {
  209. let expected = self.total() as f32;
  210. let expected = (rhs * expected).ceil() as usize;
  211. let mut fighter = (rhs * self.fighter as f32) as usize;
  212. let mut bomber = (rhs * self.bomber as f32) as usize;
  213. let mut transporter = (rhs * self.transporter as f32) as usize;
  214. let mut actual = fighter.saturating_add(bomber).saturating_add(transporter);
  215. if actual < expected && fighter < self.fighter {
  216. fighter += 1;
  217. actual += 1;
  218. }
  219. if actual < expected && bomber < self.bomber {
  220. bomber += 1;
  221. actual += 1;
  222. }
  223. if actual < expected && transporter < self.transporter {
  224. transporter += 1;
  225. actual += 1;
  226. }
  227. ShipCount {
  228. fighter,
  229. bomber,
  230. transporter,
  231. }
  232. }
  233. }
  234. /* ShipsData */
  235. impl Index<usize> for ShipsData {
  236. type Output = ShipData;
  237. fn index(&self, index: usize) -> &Self::Output {
  238. match index {
  239. 0 => &self.fighter,
  240. 1 => &self.bomber,
  241. 2 => &self.transporter,
  242. x => panic!("Invalid ships data index: {}", x),
  243. }
  244. }
  245. }
  246. impl Index<ShipType> for ShipsData {
  247. type Output = ShipData;
  248. fn index(&self, index: ShipType) -> &Self::Output {
  249. match index {
  250. ShipType::Fighter => &self.fighter,
  251. ShipType::Bomber => &self.bomber,
  252. ShipType::Transporter => &self.transporter,
  253. }
  254. }
  255. }