player.rs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. #[derive(Component)]
  44. enum GameEvent {
  45. MoveTo { destination: usize },
  46. Attack { target: Entity },
  47. }
  48. struct HandleInputEvent;
  49. impl<'a> System<'a> for HandleInputEvent {
  50. type SystemData = (
  51. Write<'a, InputEvent>,
  52. ReadExpect<'a, Map>,
  53. Entities<'a>,
  54. ReadStorage<'a, Player>,
  55. ReadStorage<'a, Position>,
  56. ReadStorage<'a, CombatStats>,
  57. WriteStorage<'a, GameEvent>,
  58. );
  59. fn run(&mut self, (mut event, map, entities, player, position, stats, mut game_events): Self::SystemData) {
  60. match *event {
  61. InputEvent::PlayerMovement { delta_x, delta_y } => {
  62. for (e, _, pos) in (&entities, &player, &position).join() {
  63. // depending on what's in the target cell, we
  64. // either want to attack or move
  65. let destination = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
  66. if let Some(target) = map.get_attackable(destination, &stats) {
  67. game_events.insert(e, GameEvent::Attack { target }).expect("Unable to add GameEvent");
  68. } else {
  69. game_events.insert(e, GameEvent::MoveTo { destination }).expect("Unable to add GameEvent");
  70. }
  71. }
  72. },
  73. InputEvent::NoAction => {}
  74. }
  75. *event = InputEvent::NoAction;
  76. }
  77. }
  78. /// This type represents all the "low-level" actions we have available
  79. /// to us, corresponding directly to the set of actions we have bound
  80. /// on the keys
  81. enum InputEvent {
  82. // attempt to move the player some amount in the given direction
  83. // (delta_x and delta_y should be -1, 0, or 1)
  84. PlayerMovement {
  85. delta_x: i32,
  86. delta_y: i32,
  87. },
  88. // do not take any action at all
  89. NoAction,
  90. }
  91. impl Default for InputEvent {
  92. // the default for an InputEvent is of course NoAction
  93. fn default() -> InputEvent {
  94. InputEvent::NoAction
  95. }
  96. }
  97. pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
  98. // Player movement
  99. match ctx.key {
  100. None => return RunState::AwaitingInput, // Nothing happened
  101. Some(key) => match key {
  102. VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H =>
  103. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: -1, delta_y: 0 }),
  104. VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L =>
  105. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: 1, delta_y: 0 }),
  106. VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K =>
  107. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: 0, delta_y: -1 }),
  108. VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J =>
  109. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: 0, delta_y: 1 }),
  110. // Diagonals
  111. VirtualKeyCode::Numpad9 | VirtualKeyCode::U =>
  112. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: 1, delta_y: -1 }),
  113. VirtualKeyCode::Numpad7 | VirtualKeyCode::Y =>
  114. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: -1, delta_y: -1 }),
  115. VirtualKeyCode::Numpad3 | VirtualKeyCode::N =>
  116. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: 1, delta_y: 1 }),
  117. VirtualKeyCode::Numpad1 | VirtualKeyCode::B =>
  118. gs.ecs.insert(InputEvent::PlayerMovement { delta_x: -1, delta_y: 1 }),
  119. _ => return RunState::AwaitingInput,
  120. },
  121. }
  122. RunState::PlayerTurn
  123. }