player.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. use rltk::{Rltk, VirtualKeyCode};
  2. use crate::{CombatStats, Map, Position, MoveEvent, RunState, State, WantsToMelee, InputEvent};
  3. use specs::prelude::*;
  4. /// Handles converting low-level `InputEvent` components (which may
  5. /// represent one of several actions, or even a completely invalid
  6. /// action such as walking into a wall) and dispatches them to the
  7. /// relevant high-level intention (e.g. moving in a direction or
  8. /// attacking a target)
  9. pub struct HandleInputEvent;
  10. impl<'a> System<'a> for HandleInputEvent {
  11. type SystemData = (
  12. WriteStorage<'a, InputEvent>,
  13. ReadExpect<'a, Map>,
  14. Entities<'a>,
  15. ReadStorage<'a, Position>,
  16. ReadStorage<'a, CombatStats>,
  17. WriteStorage<'a, WantsToMelee>,
  18. WriteStorage<'a, MoveEvent>,
  19. );
  20. fn run(&mut self, (mut event, map, entities, position, stats, mut attack, mut mov): Self::SystemData) {
  21. for (e, ev, pos) in (&entities, &event, &position).join() {
  22. match *ev {
  23. InputEvent::PlayerMovement { delta_x, delta_y } => {
  24. // depending on what's in the target cell, we
  25. // either want to attack or move
  26. let tgt_x = pos.x + delta_x;
  27. let tgt_y = pos.y + delta_y;
  28. let destination = map.xy_idx(tgt_x, tgt_y);
  29. if let Some(target) = map.get_attackable(destination, &stats) {
  30. attack.insert(e, WantsToMelee { target })
  31. .expect("Unable to add WantsToAttack");
  32. } else {
  33. mov.insert(e, MoveEvent { destination, tgt_x, tgt_y })
  34. .expect("Unable to add MoveEvent");
  35. }
  36. }
  37. }
  38. }
  39. event.clear();
  40. }
  41. }
  42. /// Translates keyboard input into the appropriate `InputEvent` value
  43. pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
  44. let player = *gs.ecs.fetch::<Entity>();
  45. let mut input = gs.ecs.write_storage::<InputEvent>();
  46. // Player movement
  47. match ctx.key {
  48. None => return RunState::AwaitingInput, // Nothing happened
  49. Some(key) => match key {
  50. VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H =>
  51. input.insert(player, InputEvent::PlayerMovement { delta_x: -1, delta_y: 0 }),
  52. VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L =>
  53. input.insert(player, InputEvent::PlayerMovement { delta_x: 1, delta_y: 0 }),
  54. VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K =>
  55. input.insert(player, InputEvent::PlayerMovement { delta_x: 0, delta_y: -1 }),
  56. VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J =>
  57. input.insert(player, InputEvent::PlayerMovement { delta_x: 0, delta_y: 1 }),
  58. // Diagonals
  59. VirtualKeyCode::Numpad9 | VirtualKeyCode::U =>
  60. input.insert(player, InputEvent::PlayerMovement { delta_x: 1, delta_y: -1 }),
  61. VirtualKeyCode::Numpad7 | VirtualKeyCode::Y =>
  62. input.insert(player, InputEvent::PlayerMovement { delta_x: -1, delta_y: -1 }),
  63. VirtualKeyCode::Numpad3 | VirtualKeyCode::N =>
  64. input.insert(player, InputEvent::PlayerMovement { delta_x: 1, delta_y: 1 }),
  65. VirtualKeyCode::Numpad1 | VirtualKeyCode::B =>
  66. input.insert(player, InputEvent::PlayerMovement { delta_x: -1, delta_y: 1 }),
  67. _ => return RunState::AwaitingInput,
  68. },
  69. }.expect("Unable to insert player movement");
  70. RunState::PlayerTurn
  71. }