player.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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. pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
  8. let mut positions = ecs.write_storage::<Position>();
  9. let players = ecs.read_storage::<Player>();
  10. let mut viewsheds = ecs.write_storage::<Viewshed>();
  11. let entities = ecs.entities();
  12. let combat_stats = ecs.read_storage::<CombatStats>();
  13. let map = ecs.fetch::<Map>();
  14. let mut wants_to_melee = ecs.write_storage::<WantsToMelee>();
  15. for (entity, _player, pos, viewshed) in
  16. (&entities, &players, &mut positions, &mut viewsheds).join()
  17. {
  18. let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
  19. for potential_target in map.tile_content[destination_idx].iter() {
  20. let target = combat_stats.get(*potential_target);
  21. if let Some(_target) = target {
  22. wants_to_melee
  23. .insert(
  24. entity,
  25. WantsToMelee {
  26. target: *potential_target,
  27. },
  28. )
  29. .expect("Add target failed");
  30. return;
  31. }
  32. }
  33. if !map.blocked[destination_idx] {
  34. pos.x = min(79, max(0, pos.x + delta_x));
  35. pos.y = min(49, max(0, pos.y + delta_y));
  36. viewshed.dirty = true;
  37. let mut ppos = ecs.write_resource::<Point>();
  38. ppos.x = pos.x;
  39. ppos.y = pos.y;
  40. }
  41. }
  42. }
  43. /// This type represents all the "low-level" actions we have available
  44. /// to us, corresponding directly to the set of actions we have bound
  45. /// on the keys
  46. enum InputEvent {
  47. // attempt to move the player some amount in the given direction
  48. // (delta_x and delta_y should be -1, 0, or 1)
  49. PlayerMovement {
  50. delta_x: i32,
  51. delta_y: i32,
  52. },
  53. // quit the game
  54. QuitGame,
  55. // do not take any action at all
  56. NoAction,
  57. }
  58. impl Default for InputEvent {
  59. // the default for an InputEvent is of course NoAction
  60. fn default() -> InputEvent {
  61. InputEvent::NoAction
  62. }
  63. }
  64. pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
  65. // Player movement
  66. match ctx.key {
  67. None => return RunState::AwaitingInput, // Nothing happened
  68. Some(key) => match key {
  69. VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H =>
  70. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: -1, delta_y: 0 }),
  71. VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L =>
  72. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: 1, delta_y: 0 }),
  73. VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K =>
  74. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: 0, delta_y: -1 }),
  75. VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J =>
  76. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: 0, delta_y: 1 }),
  77. // Diagonals
  78. VirtualKeyCode::Numpad9 | VirtualKeyCode::U =>
  79. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: 1, delta_y: -1 }),
  80. VirtualKeyCode::Numpad7 | VirtualKeyCode::Y =>
  81. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: -1, delta_y: -1 }),
  82. VirtualKeyCode::Numpad3 | VirtualKeyCode::N =>
  83. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: 1, delta_y: 1 }),
  84. VirtualKeyCode::Numpad1 | VirtualKeyCode::B =>
  85. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: -1, delta_y: 1 }),
  86. VirtualKeyCode::Q | VirtualKeyCode::Escape =>
  87. gs.ecs.insert(InputEvent::QuitGame),
  88. _ => return RunState::AwaitingInput,
  89. },
  90. }
  91. RunState::PlayerTurn
  92. }