From e4be3b6855745e0261764068a12ee363db150537 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Thu, 4 Nov 2021 09:40:58 -0400 Subject: [PATCH] Add ability to drop items --- src/components.rs | 5 +++ src/gui.rs | 87 +++++++++++++++++++++++++++++++++++++++++ src/inventory_system.rs | 58 ++++++++++++++++++++++++++- src/main.rs | 27 ++++++++++++- src/player.rs | 3 ++ 5 files changed, 178 insertions(+), 2 deletions(-) diff --git a/src/components.rs b/src/components.rs index de0a671..ec07bdc 100644 --- a/src/components.rs +++ b/src/components.rs @@ -90,3 +90,8 @@ 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 cf3d988..37a7d4a 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -247,3 +247,90 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option }, } } + +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) + } + }, + } +} diff --git a/src/inventory_system.rs b/src/inventory_system.rs index af2ee28..fd14c70 100644 --- a/src/inventory_system.rs +++ b/src/inventory_system.rs @@ -1,6 +1,6 @@ use crate::{ gamelog::GameLog, CombatStats, InBackpack, Name, Position, Potion, WantsToDrinkPotion, - WantsToPickupItem, + WantsToDropItem, WantsToPickupItem, }; use specs::prelude::*; @@ -91,3 +91,59 @@ impl<'a> System<'a> for PotionUseSystem { wants_drink.clear(); } } + +pub struct ItemDropSystem {} + +impl<'a> System<'a> for ItemDropSystem { + 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 drop item to 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 65f3b46..821758f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ mod visibility_system; pub use components::*; use damage_system::DamageSystem; pub use gamelog::GameLog; -use inventory_system::{ItemCollectionSystem, PotionUseSystem}; +use inventory_system::{ItemCollectionSystem, ItemDropSystem, PotionUseSystem}; pub use map::*; use map_indexing_system::MapIndexingSystem; use melee_combat_system::MeleeCombatSystem; @@ -36,6 +36,7 @@ pub enum RunState { PlayerTurn, MonsterTurn, ShowInventory, + ShowDropItem, } pub struct State { @@ -65,6 +66,9 @@ impl State { let mut potions = PotionUseSystem {}; potions.run_now(&self.ecs); + let mut drop_items = ItemDropSystem {}; + drop_items.run_now(&self.ecs); + self.ecs.maintain(); } } @@ -118,6 +122,26 @@ 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("failed to add intent to drop item"); + + newrunstate = RunState::PlayerTurn; + } + } + } } { @@ -169,6 +193,7 @@ fn main() -> rltk::BError { gs.ecs.register::(); gs.ecs.register::(); gs.ecs.register::(); + gs.ecs.register::(); let map: Map = Map::new_map_rooms_and_corridors(); let (player_x, player_y) = map.rooms[0].center(); diff --git a/src/player.rs b/src/player.rs index e0c66d0..5098d83 100644 --- a/src/player.rs +++ b/src/player.rs @@ -101,6 +101,9 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState { // Show inventory VirtualKeyCode::I => return RunState::ShowInventory, + // Show item drop screen + VirtualKeyCode::D => return RunState::ShowDropItem, + _ => return RunState::AwaitingInput, }, }