From 433d5c00f32fe07aa8a0ee87c2a8102fbdf0e668 Mon Sep 17 00:00:00 2001 From: Benjamyn Love Date: Sun, 20 Nov 2022 16:10:11 +1100 Subject: [PATCH] Drop items --- src/components.rs | 7 ++++++- src/gui.rs | 45 +++++++++++++++++++++++++++++++++++++++++ src/inventory_system.rs | 36 ++++++++++++++++++++++++++++++++- src/main.rs | 29 ++++++++++++++++++++++++++ src/player.rs | 1 + 5 files changed, 116 insertions(+), 2 deletions(-) diff --git a/src/components.rs b/src/components.rs index 10116cf..bcc7db9 100644 --- a/src/components.rs +++ b/src/components.rs @@ -1,4 +1,4 @@ -use rltk::RGB; +use rltk::{RGB}; use specs::prelude::*; use specs_derive::*; @@ -40,6 +40,7 @@ pub enum RunState { PlayerTurn, MonsterTurn, ShowInventory, + ShowDropItem } #[derive(Component, Debug)] @@ -99,3 +100,7 @@ pub struct WantsToPickupItem { pub struct WantsToDrinkPotion { pub potion: Entity, } +#[derive(Component, Debug, Clone)] +pub struct WantsToDropItem { + pub item : Entity +} diff --git a/src/gui.rs b/src/gui.rs index 7a1945f..a707db4 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -129,4 +129,49 @@ pub fn show_inventory(gs : &mut State, ctx : &mut Rltk) -> (ItemMenuResult, Opti } } +} + +pub fn drop_item_menu(gs: &mut State, ctx : &mut Rltk) -> (ItemMenuResult, Option) { + let player_entity = gs.ecs.fetch::(); + let names = gs.ecs.read_storage::(); + let backpack = gs.ecs.read_storage::(); + let entities = gs.ecs.entities(); + + let inventory = (&backpack, &names).join().filter(|item| item.0.owner == *player_entity); + let count = inventory.count(); + + let mut y = (25 - (count / 2)) as i32; + ctx.draw_box(15, y-2, 31, (count + 3) as i32, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK)); + ctx.print_color(18, y-2, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "Drop which item?"); + ctx.print_color(18, y + count as i32 + 1, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "Escape to cancel"); + + let mut equippable : Vec = Vec::new(); + let mut j = 0; + for (entity, _pack, name) in (&entities, &backpack, &names).join().filter(|item| item.1.owner == *player_entity) { + ctx.set(17, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), rltk::to_cp437('(')); + ctx.set(18, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 97 + j as rltk::FontCharType); + ctx.set(19, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), rltk::to_cp437(')')); + + ctx.print(21, y, &name.name.to_string()); + equippable.push(entity); + y+=1; + j+=1; + } + + match ctx.key { + None => (ItemMenuResult::NoResponse, None), + Some(key) => { + match (key) { + VirtualKeyCode::Escape => { (ItemMenuResult::Cancel, None)}, + _ => { + let selection = rltk::letter_to_option(key); + if selection >= -1 && selection < count as i32 { + return (ItemMenuResult::Selected, Some(equippable[selection as usize])); + } + (ItemMenuResult::NoResponse, None) + } + } + } + } + } \ No newline at end of file diff --git a/src/inventory_system.rs b/src/inventory_system.rs index 5d06f0f..beab1f0 100644 --- a/src/inventory_system.rs +++ b/src/inventory_system.rs @@ -2,7 +2,7 @@ use specs::prelude::*; use super::{ gamelog::GameLog, CombatStats, InBackpack, Name, Position, Potion, WantsToDrinkPotion, - WantsToPickupItem, + WantsToPickupItem,WantsToDropItem }; pub struct ItemCollectionSystem {} @@ -91,3 +91,37 @@ impl<'a> System<'a> for PotionUseSystem { wants_drink.clear(); } } +pub struct ItemDropSystem {} + +impl<'a> System<'a> for ItemDropSystem { + #[allow(clippy::type_complexity)] + type SystemData = ( ReadExpect<'a, Entity>, + WriteExpect<'a, GameLog>, + Entities<'a>, + WriteStorage<'a, WantsToDropItem>, + ReadStorage<'a, Name>, + WriteStorage<'a, Position>, + WriteStorage<'a, InBackpack> + ); + + fn run(&mut self, data : Self::SystemData) { + let (player_entity, mut gamelog, entities, mut wants_drop, names, mut positions, mut backpack) = data; + + for (entity, to_drop) in (&entities, &wants_drop).join() { + let mut dropper_pos : Position = Position{x:0, y:0}; + { + let dropped_pos = positions.get(entity).unwrap(); + dropper_pos.x = dropped_pos.x; + dropper_pos.y = dropped_pos.y; + } + positions.insert(to_drop.item, Position{ x : dropper_pos.x, y : dropper_pos.y}).expect("Unable to insert position"); + backpack.remove(to_drop.item); + + if entity == *player_entity { + gamelog.entries.push(format!("You drop the {}", names.get(to_drop.item).unwrap().name)); + } + } + + wants_drop.clear(); + } +} diff --git a/src/main.rs b/src/main.rs index 59a9486..ea3f980 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,6 +58,8 @@ impl State { damage_system.run_now(&self.ecs); let mut pickup = ItemCollectionSystem {}; pickup.run_now(&self.ecs); + let mut drop_items = ItemDropSystem{}; + drop_items.run_now(&self.ecs); let mut potions = PotionUseSystem {}; potions.run_now(&self.ecs); self.ecs.maintain(); @@ -128,6 +130,32 @@ impl GameState for State { } } } + RunState::ShowDropItem => { + let result = gui::drop_item_menu(self, ctx); + match result.0 { + gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput, + gui::ItemMenuResult::NoResponse => {}, + gui::ItemMenuResult::Selected => { + let item_entity = result.1.unwrap(); + let mut intent = self.ecs.write_storage::(); + intent.insert(*self.ecs.fetch::(), WantsToDropItem { item: item_entity }).expect("Unable to insert intent"); + newrunstate = RunState::PlayerTurn; + } + } + } + RunState::ShowDropItem => { + let result = gui::drop_item_menu(self, ctx); + match result.0 { + gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput, + gui::ItemMenuResult::NoResponse => {}, + gui::ItemMenuResult::Selected => { + let item_entity = result.1.unwrap(); + let mut intent = self.ecs.write_storage::(); + intent.insert(*self.ecs.fetch::(), WantsToDropItem { item: item_entity }).expect("Unable to insert intent"); + newrunstate = RunState::PlayerTurn; + } + } + } } { @@ -160,6 +188,7 @@ fn main() -> rltk::BError { gs.ecs.register::(); gs.ecs.register::(); gs.ecs.register::(); + gs.ecs.register::(); gs.ecs.register::(); let map = Map::new_map_rooms_and_corridors(); diff --git a/src/player.rs b/src/player.rs index 096a00b..e5c71bd 100644 --- a/src/player.rs +++ b/src/player.rs @@ -86,6 +86,7 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState { VirtualKeyCode::Numpad1 | VirtualKeyCode::B => {try_move_player(-1, 1, &mut gs.ecs)} VirtualKeyCode::G => get_item(&mut gs.ecs), VirtualKeyCode::I => return RunState::ShowInventory, + VirtualKeyCode::D => return RunState::ShowDropItem, _ => return RunState::AwaitingInput, }, }