player.rs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. extern crate rltk;
  2. use rltk::{Point, Rltk, VirtualKeyCode};
  3. extern crate specs;
  4. use super::{CombatStats, Map, Player, Position, RunState, State, Viewshed, WantsToMelee};
  5. use specs::prelude::*;
  6. use std::cmp::{max, min};
  7. fn clamp<T: PartialOrd>(low: T, high: T, val: T) -> T {
  8. if val < low {
  9. low
  10. } else if val > high {
  11. high
  12. } else {
  13. val
  14. }
  15. }
  16. #[derive(Component)]
  17. pub enum GameEvent {
  18. MoveTo {
  19. destination: usize,
  20. tgt_x: i32,
  21. tgt_y: i32,
  22. },
  23. Attack { target: Entity },
  24. }
  25. pub struct HandleGameEvent;
  26. impl<'a> System<'a> for HandleGameEvent {
  27. type SystemData = (
  28. Entities<'a>,
  29. WriteStorage<'a, GameEvent>,
  30. WriteStorage<'a, WantsToMelee>,
  31. WriteStorage<'a, Position>,
  32. WriteStorage<'a, Viewshed>,
  33. WriteExpect<'a, Point>,
  34. ReadExpect<'a, Map>,
  35. );
  36. fn run(&mut self, (entities, mut game_events, mut melee, mut pos, mut viewshed, mut point, map): Self::SystemData) {
  37. for (e, event) in (&entities, &game_events).join() {
  38. match event {
  39. GameEvent::Attack { target } => {
  40. melee.insert(e, WantsToMelee { target: *target })
  41. .expect("Unable to add melee intention for player");
  42. }
  43. GameEvent::MoveTo { destination, tgt_x, tgt_y } => {
  44. if !map.blocked[*destination] {
  45. viewshed.get_mut(e).expect("Unable to find viewshed").dirty = true;
  46. pos.get_mut(e).expect("Unable to find position").x = *tgt_x;
  47. pos.get_mut(e).expect("Unable to find position").y = *tgt_y;
  48. point.x = clamp(0, 79, *tgt_x);
  49. point.y = clamp(0, 49, *tgt_y);
  50. }
  51. }
  52. }
  53. }
  54. game_events.clear();
  55. }
  56. }
  57. pub struct HandleInputEvent;
  58. impl<'a> System<'a> for HandleInputEvent {
  59. type SystemData = (
  60. WriteStorage<'a, InputEvent>,
  61. ReadExpect<'a, Map>,
  62. Entities<'a>,
  63. ReadStorage<'a, Position>,
  64. ReadStorage<'a, CombatStats>,
  65. WriteStorage<'a, GameEvent>,
  66. );
  67. fn run(&mut self, (mut event, map, entities, position, stats, mut game_events): Self::SystemData) {
  68. for (e, ev, pos) in (&entities, &event, &position).join() {
  69. match *ev {
  70. InputEvent::PlayerMovement { delta_x, delta_y } => {
  71. // depending on what's in the target cell, we
  72. // either want to attack or move
  73. let tgt_x = pos.x + delta_x;
  74. let tgt_y = pos.y + delta_y;
  75. let destination = map.xy_idx(tgt_x, tgt_y);
  76. if let Some(target) = map.get_attackable(destination, &stats) {
  77. game_events.insert(e, GameEvent::Attack { target })
  78. .expect("Unable to add GameEvent");
  79. } else {
  80. game_events.insert(e, GameEvent::MoveTo { destination, tgt_x, tgt_y })
  81. .expect("Unable to add GameEvent");
  82. }
  83. }
  84. }
  85. }
  86. event.clear();
  87. }
  88. }
  89. /// This type represents all the "low-level" actions we have available
  90. /// to us, corresponding directly to the set of actions we have bound
  91. /// on the keys
  92. #[derive(Component)]
  93. pub enum InputEvent {
  94. // attempt to move the player some amount in the given direction
  95. // (delta_x and delta_y should be -1, 0, or 1)
  96. PlayerMovement {
  97. delta_x: i32,
  98. delta_y: i32,
  99. },
  100. }
  101. pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
  102. let player = *gs.ecs.fetch::<Entity>();
  103. let mut input = gs.ecs.write_storage::<InputEvent>();
  104. // Player movement
  105. match ctx.key {
  106. None => return RunState::AwaitingInput, // Nothing happened
  107. Some(key) => match key {
  108. VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H =>
  109. input.insert(player, InputEvent::PlayerMovement { delta_x: -1, delta_y: 0 }),
  110. VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L =>
  111. input.insert(player, InputEvent::PlayerMovement { delta_x: 1, delta_y: 0 }),
  112. VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K =>
  113. input.insert(player, InputEvent::PlayerMovement { delta_x: 0, delta_y: -1 }),
  114. VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J =>
  115. input.insert(player, InputEvent::PlayerMovement { delta_x: 0, delta_y: 1 }),
  116. // Diagonals
  117. VirtualKeyCode::Numpad9 | VirtualKeyCode::U =>
  118. input.insert(player, InputEvent::PlayerMovement { delta_x: 1, delta_y: -1 }),
  119. VirtualKeyCode::Numpad7 | VirtualKeyCode::Y =>
  120. input.insert(player, InputEvent::PlayerMovement { delta_x: -1, delta_y: -1 }),
  121. VirtualKeyCode::Numpad3 | VirtualKeyCode::N =>
  122. input.insert(player, InputEvent::PlayerMovement { delta_x: 1, delta_y: 1 }),
  123. VirtualKeyCode::Numpad1 | VirtualKeyCode::B =>
  124. input.insert(player, InputEvent::PlayerMovement { delta_x: -1, delta_y: 1 }),
  125. _ => return RunState::AwaitingInput,
  126. },
  127. }.expect("Unable to insert player movement");
  128. RunState::PlayerTurn
  129. }