From 3e2eee97090683342557950c42c226c42a9602ed Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Mon, 24 Jul 2023 00:58:40 +0100 Subject: [PATCH] ActionWithDirection runstate - setting this runstate with a function as arg will give a direction prompt, and then call the function with the selected direction as the argument. i.e. for opening a door or throwing an item in a specific direction --- src/gui.rs | 28 +++++++++++++++++++++-- src/main.rs | 4 ++++ src/player.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/gui.rs b/src/gui.rs index 8a3e850..40b5f06 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,6 +1,6 @@ use super::{ - gamelog, rex_assets::RexAssets, CombatStats, Equipped, Hidden, HungerClock, HungerState, InBackpack, Map, Name, - Player, Point, Position, RunState, State, Viewshed, + gamelog, player::try_door, rex_assets::RexAssets, CombatStats, Equipped, Hidden, HungerClock, HungerState, + InBackpack, Map, Name, Player, Point, Position, RunState, State, Viewshed, }; use rltk::{Rltk, VirtualKeyCode, RGB}; use specs::prelude::*; @@ -58,6 +58,30 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { draw_tooltips(ecs, ctx); } +pub fn get_input_direction( + ecs: &mut World, + ctx: &mut Rltk, + function: fn(i: i32, j: i32, ecs: &mut World) -> RunState, +) -> RunState { + ctx.print_color(1, 1, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "In what direction? [0-9]/[YUHJKLBN]"); + match ctx.key { + None => return RunState::ActionWithDirection { function }, + Some(key) => match key { + // Cardinals + VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => return function(-1, 0, ecs), + VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => return function(1, 0, ecs), + VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => return function(0, -1, ecs), + VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => return function(0, 1, ecs), + // Diagonals + VirtualKeyCode::Numpad9 | VirtualKeyCode::U => return function(1, -1, ecs), + VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => return function(-1, -1, ecs), + VirtualKeyCode::Numpad3 | VirtualKeyCode::N => return function(1, 1, ecs), + VirtualKeyCode::Numpad1 | VirtualKeyCode::B => return function(-1, 1, ecs), + _ => return RunState::ActionWithDirection { function }, + }, + } +} + fn draw_tooltips(ecs: &World, ctx: &mut Rltk) { let map = ecs.fetch::(); let names = ecs.read_storage::(); diff --git a/src/main.rs b/src/main.rs index 4fb8d06..fa49fa1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,6 +56,7 @@ pub enum RunState { ShowDropItem, ShowRemoveItem, ShowTargeting { range: i32, item: Entity, aoe: i32 }, + ActionWithDirection { function: fn(i: i32, j: i32, ecs: &mut World) -> RunState }, MainMenu { menu_selection: gui::MainMenuSelection }, SaveGame, GameOver, @@ -398,6 +399,9 @@ impl GameState for State { } } } + RunState::ActionWithDirection { function } => { + new_runstate = gui::get_input_direction(&mut self.ecs, ctx, try_door); + } RunState::MainMenu { .. } => { let result = gui::main_menu(self, ctx); match result { diff --git a/src/player.rs b/src/player.rs index eb8164a..cf0404c 100644 --- a/src/player.rs +++ b/src/player.rs @@ -7,6 +7,65 @@ use rltk::{Point, RandomNumberGenerator, Rltk, VirtualKeyCode}; use specs::prelude::*; use std::cmp::{max, min}; +pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState { + let mut positions = ecs.write_storage::(); + let mut players = ecs.write_storage::(); + let mut viewsheds = ecs.write_storage::(); + let map = ecs.fetch::(); + + let entities = ecs.entities(); + let mut doors = ecs.write_storage::(); + let mut blocks_visibility = ecs.write_storage::(); + let mut blocks_movement = ecs.write_storage::(); + let mut renderables = ecs.write_storage::(); + let names = ecs.read_storage::(); + + for (_entity, _player, pos, viewshed) in (&entities, &mut players, &mut positions, &mut viewsheds).join() { + let delta_x = i; + let delta_y = j; + + if !(pos.x + delta_x < 1 + || pos.x + delta_x > map.width - 1 + || pos.y + delta_y < 1 + || pos.y + delta_y > map.height - 1) + { + let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y); + + for potential_target in map.tile_content[destination_idx].iter() { + let door = doors.get_mut(*potential_target); + if let Some(door) = door { + if door.open == true { + if map.tile_content[destination_idx].len() > 1 { + if let Some(name) = names.get(*potential_target) { + gamelog::Logger::new().append("The").item_name(&name.name).append("is blocked.").log(); + } + } else { + door.open = false; + blocks_visibility + .insert(*potential_target, BlocksVisibility {}) + .expect("Unable to insert BlocksVisibility."); + blocks_movement + .insert(*potential_target, BlocksTile {}) + .expect("Unable to insert BlocksTile."); + let render_data = renderables.get_mut(*potential_target).unwrap(); + if let Some(name) = names.get(*potential_target) { + gamelog::Logger::new().append("You close the").item_name_n(&name.name).period().log(); + } + render_data.glyph = rltk::to_cp437('+'); // Nethack open door, maybe just use '/' instead. + viewshed.dirty = true; + return RunState::PlayerTurn; + } + } else { + gamelog::Logger::new().append("It's already closed."); + } + } + } + } + } + gamelog::Logger::new().append("You see no door there."); + return RunState::AwaitingInput; +} + pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> bool { let mut positions = ecs.write_storage::(); let mut players = ecs.write_storage::(); @@ -47,7 +106,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> bool { blocks_visibility.remove(*potential_target); blocks_movement.remove(*potential_target); let render_data = renderables.get_mut(*potential_target).unwrap(); - if let Some(name) = names.get(entity) { + if let Some(name) = names.get(*potential_target) { gamelog::Logger::new().append("You open the").item_name_n(&name.name).period().log(); } render_data.glyph = rltk::to_cp437('▓'); // Nethack open door, maybe just use '/' instead. @@ -179,6 +238,7 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState { } // Items + VirtualKeyCode::C => return RunState::ActionWithDirection { function: try_door }, VirtualKeyCode::G => { result = get_item(&mut gs.ecs); }