use crate::{CombatStats, InputEvent, Map, MoveEvent, Position, RunState, State, WantsToMelee}; use rltk::{Rltk, VirtualKeyCode}; use specs::prelude::*; /// Handles converting low-level `InputEvent` components (which may /// represent one of several actions, or even a completely invalid /// action such as walking into a wall) and dispatches them to the /// relevant high-level intention (e.g. moving in a direction or /// attacking a target) pub struct HandleInputEvent; impl<'a> System<'a> for HandleInputEvent { type SystemData = ( WriteStorage<'a, InputEvent>, ReadExpect<'a, Map>, Entities<'a>, ReadStorage<'a, Position>, ReadStorage<'a, CombatStats>, WriteStorage<'a, WantsToMelee>, WriteStorage<'a, MoveEvent>, ); fn run( &mut self, (mut event, map, entities, position, stats, mut attack, mut mov): Self::SystemData, ) { for (e, ev, pos) in (&entities, &event, &position).join() { match *ev { InputEvent::PlayerMovement { delta_x, delta_y } => { // depending on what's in the target cell, we // either want to attack or move let tgt_x = pos.x + delta_x; let tgt_y = pos.y + delta_y; let destination = map.xy_idx(tgt_x, tgt_y); if let Some(target) = map.get_attackable(destination, &stats) { attack .insert(e, WantsToMelee { target }) .expect("Unable to add WantsToAttack"); } else { mov.insert( e, MoveEvent { destination, tgt_x, tgt_y, }, ) .expect("Unable to add MoveEvent"); } } } } event.clear(); } } /// Translates keyboard input into the appropriate `InputEvent` value pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState { let player = *gs.ecs.fetch::(); let mut input = gs.ecs.write_storage::(); // Player movement match ctx.key { None => return RunState::AwaitingInput, // Nothing happened Some(key) => match key { VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => input.insert( player, InputEvent::PlayerMovement { delta_x: -1, delta_y: 0, }, ), VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => input.insert( player, InputEvent::PlayerMovement { delta_x: 1, delta_y: 0, }, ), VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => input.insert( player, InputEvent::PlayerMovement { delta_x: 0, delta_y: -1, }, ), VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => input.insert( player, InputEvent::PlayerMovement { delta_x: 0, delta_y: 1, }, ), // Diagonals VirtualKeyCode::Numpad9 | VirtualKeyCode::U => input.insert( player, InputEvent::PlayerMovement { delta_x: 1, delta_y: -1, }, ), VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => input.insert( player, InputEvent::PlayerMovement { delta_x: -1, delta_y: -1, }, ), VirtualKeyCode::Numpad3 | VirtualKeyCode::N => input.insert( player, InputEvent::PlayerMovement { delta_x: 1, delta_y: 1, }, ), VirtualKeyCode::Numpad1 | VirtualKeyCode::B => input.insert( player, InputEvent::PlayerMovement { delta_x: -1, delta_y: 1, }, ), _ => return RunState::AwaitingInput, }, } .expect("Unable to insert player movement"); RunState::PlayerTurn }