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.

199 lines
5.6 KiB

  1. use glc::vector::Vector2f;
  2. use shrev::{EventChannel, ReaderId};
  3. use specs::{
  4. prelude::*, Entities, Entity, LazyUpdate, ReadExpect, ReadStorage, System, World, WriteStorage,
  5. };
  6. use crate::{
  7. components::{
  8. Fleet, FleetMoving, FleetOrbiting, MeetingPoint, PlayerOwned, Position, Ship, ShipCount,
  9. ShipType,
  10. },
  11. misc::{LogResult, WorldHelper},
  12. systems::ShipControlEvent,
  13. Error,
  14. };
  15. pub struct FleetControl {
  16. fleet_control_event_id: ReaderId<FleetControlEvent>,
  17. }
  18. #[derive(Debug)]
  19. pub enum FleetControlEvent {
  20. MoveToMeetingPoint {
  21. fleet: Entity,
  22. count: ShipCount,
  23. target: Entity,
  24. },
  25. MoveToPosition {
  26. fleet: Entity,
  27. count: ShipCount,
  28. target: Vector2f,
  29. },
  30. }
  31. #[derive(SystemData)]
  32. pub struct FleetControlData<'a> {
  33. fleet_control_events: ReadExpect<'a, EventChannel<FleetControlEvent>>,
  34. lazy: Read<'a, LazyUpdate>,
  35. entities: Entities<'a>,
  36. player_owned: WriteStorage<'a, PlayerOwned>,
  37. ship_control: WriteExpect<'a, EventChannel<ShipControlEvent>>,
  38. fleets: WriteStorage<'a, Fleet>,
  39. fleets_moving: WriteStorage<'a, FleetMoving>,
  40. fleets_orbiting: WriteStorage<'a, FleetOrbiting>,
  41. positions: WriteStorage<'a, Position>,
  42. meeting_points: WriteStorage<'a, MeetingPoint>,
  43. ships: ReadStorage<'a, Ship>,
  44. }
  45. struct Processor<'a> {
  46. lazy: Read<'a, LazyUpdate>,
  47. entities: Entities<'a>,
  48. player_owned: WriteStorage<'a, PlayerOwned>,
  49. ship_control: WriteExpect<'a, EventChannel<ShipControlEvent>>,
  50. fleets: WriteStorage<'a, Fleet>,
  51. fleets_moving: WriteStorage<'a, FleetMoving>,
  52. fleets_orbiting: WriteStorage<'a, FleetOrbiting>,
  53. positions: WriteStorage<'a, Position>,
  54. meeting_points: WriteStorage<'a, MeetingPoint>,
  55. ships: ReadStorage<'a, Ship>,
  56. }
  57. impl FleetControl {
  58. pub fn new(world: &mut World) -> Result<Self, Error> {
  59. world.insert(EventChannel::<FleetControlEvent>::default());
  60. let fleet_control_event_id = world.register_event_reader::<FleetControlEvent>()?;
  61. Ok(Self {
  62. fleet_control_event_id,
  63. })
  64. }
  65. }
  66. impl<'a> System<'a> for FleetControl {
  67. type SystemData = FleetControlData<'a>;
  68. fn run(&mut self, data: Self::SystemData) {
  69. let FleetControlData {
  70. fleet_control_events,
  71. lazy,
  72. entities,
  73. player_owned,
  74. ship_control,
  75. fleets,
  76. fleets_moving,
  77. fleets_orbiting,
  78. positions,
  79. meeting_points,
  80. ships,
  81. } = data;
  82. let mut processor = Processor {
  83. lazy,
  84. entities,
  85. player_owned,
  86. ship_control,
  87. fleets,
  88. fleets_moving,
  89. fleets_orbiting,
  90. positions,
  91. meeting_points,
  92. ships,
  93. };
  94. let events = fleet_control_events.read(&mut self.fleet_control_event_id);
  95. for event in events {
  96. match event {
  97. FleetControlEvent::MoveToPosition {
  98. fleet,
  99. count,
  100. target,
  101. } => {
  102. processor.move_to_position(*fleet, *count, *target);
  103. }
  104. FleetControlEvent::MoveToMeetingPoint {
  105. fleet,
  106. count,
  107. target,
  108. } => {
  109. processor.move_to_meeting_point(*fleet, *count, *target);
  110. }
  111. }
  112. }
  113. }
  114. }
  115. impl Processor<'_> {
  116. fn move_to_position(&mut self, fleet: Entity, count: ShipCount, target: Vector2f) {
  117. let target = self.create_meeting_point(target);
  118. self.move_to_meeting_point(fleet, count, target);
  119. }
  120. fn move_to_meeting_point(&mut self, fleet: Entity, mut count: ShipCount, target: Entity) {
  121. let player_owned = self.player_owned.get(fleet).unwrap();
  122. let player_id = player_owned.owner();
  123. let target_fleet = self.create_fleet(player_id, target);
  124. let source_fleet = self.fleets.get(fleet).unwrap();
  125. let data = (&self.entities, source_fleet.owned(), &self.ships);
  126. for (id, _, ship) in data.join() {
  127. match ship.type_() {
  128. ShipType::Fighter if count.fighter > 0 => {
  129. count.fighter -= 1;
  130. }
  131. ShipType::Bomber if count.bomber > 0 => {
  132. count.bomber -= 1;
  133. }
  134. ShipType::Transporter if count.transporter > 0 => {
  135. count.transporter -= 1;
  136. }
  137. _ => continue,
  138. }
  139. let event = ShipControlEvent::SetMoving {
  140. ship: id,
  141. fleet: target_fleet,
  142. };
  143. self.ship_control.single_write(event);
  144. }
  145. }
  146. fn create_meeting_point(&mut self, pos: Vector2f) -> Entity {
  147. MeetingPoint::builder()
  148. .position(pos)
  149. .lazy(
  150. &self.lazy,
  151. &self.entities,
  152. &mut self.positions,
  153. &mut self.meeting_points,
  154. )
  155. .panic("Unable to create new entity: MeetingPoint")
  156. }
  157. fn create_fleet(&mut self, player: Entity, target: Entity) -> Entity {
  158. Fleet::builder()
  159. .player(player)
  160. .moving(target)
  161. .lazy(
  162. &self.lazy,
  163. &self.entities,
  164. &mut self.player_owned,
  165. &mut self.fleets,
  166. &mut self.fleets_moving,
  167. &mut self.fleets_orbiting,
  168. )
  169. .panic("Unable to create new entitiy: Fleet")
  170. }
  171. }