player.rs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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. WriteStorage<'a, InputEvent>,
  52. ReadExpect<'a, Map>,
  53. Entities<'a>,
  54. ReadStorage<'a, Position>,
  55. ReadStorage<'a, CombatStats>,
  56. WriteStorage<'a, GameEvent>,
  57. );
  58. fn run(&mut self, (mut event, map, entities, position, stats, mut game_events): Self::SystemData) {
  59. for ev in (&event).join() {
  60. match *ev {
  61. InputEvent::PlayerMovement { delta_x, delta_y } => {
  62. for (e, pos) in (&entities, &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 })
  68. .expect("Unable to add GameEvent");
  69. } else {
  70. game_events.insert(e, GameEvent::MoveTo { destination })
  71. .expect("Unable to add GameEvent");
  72. }
  73. }
  74. }
  75. }
  76. }
  77. event.clear();
  78. }
  79. }
  80. /// This type represents all the "low-level" actions we have available
  81. /// to us, corresponding directly to the set of actions we have bound
  82. /// on the keys
  83. #[derive(Component)]
  84. enum InputEvent {
  85. // attempt to move the player some amount in the given direction
  86. // (delta_x and delta_y should be -1, 0, or 1)
  87. PlayerMovement {
  88. delta_x: i32,
  89. delta_y: i32,
  90. },
  91. }
  92. pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
  93. let player = *gs.ecs.fetch::<Entity>();
  94. let mut input = gs.ecs.write_storage::<InputEvent>();
  95. // Player movement
  96. match ctx.key {
  97. None => return RunState::AwaitingInput, // Nothing happened
  98. Some(key) => match key {
  99. VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H =>
  100. input.insert(player, InputEvent::PlayerMovement { delta_x: -1, delta_y: 0 }),
  101. VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L =>
  102. input.insert(player, InputEvent::PlayerMovement { delta_x: 1, delta_y: 0 }),
  103. VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K =>
  104. input.insert(player, InputEvent::PlayerMovement { delta_x: 0, delta_y: -1 }),
  105. VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J =>
  106. input.insert(player, InputEvent::PlayerMovement { delta_x: 0, delta_y: 1 }),
  107. // Diagonals
  108. VirtualKeyCode::Numpad9 | VirtualKeyCode::U =>
  109. input.insert(player, InputEvent::PlayerMovement { delta_x: 1, delta_y: -1 }),
  110. VirtualKeyCode::Numpad7 | VirtualKeyCode::Y =>
  111. input.insert(player, InputEvent::PlayerMovement { delta_x: -1, delta_y: -1 }),
  112. VirtualKeyCode::Numpad3 | VirtualKeyCode::N =>
  113. input.insert(player, InputEvent::PlayerMovement { delta_x: 1, delta_y: 1 }),
  114. VirtualKeyCode::Numpad1 | VirtualKeyCode::B =>
  115. input.insert(player, InputEvent::PlayerMovement { delta_x: -1, delta_y: 1 }),
  116. _ => return RunState::AwaitingInput,
  117. },
  118. };
  119. RunState::PlayerTurn
  120. }