diff --git a/src/components.rs b/src/components.rs index a23c6bd..de0a671 100644 --- a/src/components.rs +++ b/src/components.rs @@ -85,3 +85,8 @@ pub struct WantsToPickupItem { pub collected_by: Entity, pub item: Entity, } + +#[derive(Component, Debug)] +pub struct WantsToDrinkPotion { + pub potion: Entity, +} diff --git a/src/gui.rs b/src/gui.rs index afc0dc7..cf3d988 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -161,10 +161,11 @@ pub enum ItemMenuResult { Selected, } -pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> ItemMenuResult { +pub fn show_inventory(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() @@ -195,10 +196,11 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> ItemMenuResult { "ESCAPE to cancel", ); + let mut equippable: Vec = Vec::new(); let mut j = 0; - for (_pack, name) in (&backpack, &names) + for (entity, _pack, name) in (&entities, &backpack, &names) .join() - .filter(|item| item.0.owner == *player_entity) + .filter(|item| item.1.owner == *player_entity) { ctx.set( 17, @@ -223,15 +225,25 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> ItemMenuResult { ); ctx.print(21, y, &name.name.to_string()); + equippable.push(entity); y += 1; j += 1; } match ctx.key { - None => ItemMenuResult::NoResponse, + None => (ItemMenuResult::NoResponse, None), Some(key) => match key { - VirtualKeyCode::Escape => ItemMenuResult::Cancel, - _ => ItemMenuResult::NoResponse, + 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 56f9a5a..af2ee28 100644 --- a/src/inventory_system.rs +++ b/src/inventory_system.rs @@ -1,4 +1,7 @@ -use crate::{gamelog::GameLog, InBackpack, Name, Position, WantsToPickupItem}; +use crate::{ + gamelog::GameLog, CombatStats, InBackpack, Name, Position, Potion, WantsToDrinkPotion, + WantsToPickupItem, +}; use specs::prelude::*; pub struct ItemCollectionSystem {} @@ -40,3 +43,51 @@ impl<'a> System<'a> for ItemCollectionSystem { wants_pickup.clear(); } } + +pub struct PotionUseSystem {} + +impl<'a> System<'a> for PotionUseSystem { + #[allow(clippy::type_complexity)] + type SystemData = ( + ReadExpect<'a, Entity>, + WriteExpect<'a, GameLog>, + Entities<'a>, + WriteStorage<'a, WantsToDrinkPotion>, + ReadStorage<'a, Name>, + ReadStorage<'a, Potion>, + WriteStorage<'a, CombatStats>, + ); + + fn run(&mut self, data: Self::SystemData) { + let ( + player_entity, + mut gamelog, + entities, + mut wants_drink, + names, + potions, + mut combat_stats, + ) = data; + + for (entity, drink, stats) in (&entities, &wants_drink, &mut combat_stats).join() { + match potions.get(drink.potion) { + None => {} + Some(potion) => { + stats.hp = i32::min(stats.max_hp, stats.hp + potion.heal_amount); + if entity == *player_entity { + gamelog.entries.push(format!( + "You drink the {}, healing {} hp.", + names.get(drink.potion).unwrap().name, + potion.heal_amount + )); + } + entities + .delete(drink.potion) + .expect("Failed to delete potion"); + } + } + } + + wants_drink.clear(); + } +} diff --git a/src/main.rs b/src/main.rs index 84f13ac..b135113 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,7 +24,7 @@ mod gui; pub use gamelog::GameLog; mod inventory_system; mod spawner; -use inventory_system::ItemCollectionSystem; +use inventory_system::{ItemCollectionSystem, PotionUseSystem}; pub const MAP_SIZE: usize = 80 * 50; @@ -61,6 +61,9 @@ impl State { let mut pickup = ItemCollectionSystem {}; pickup.run_now(&self.ecs); + let mut potions = PotionUseSystem {}; + potions.run_now(&self.ecs); + self.ecs.maintain(); } } @@ -77,6 +80,7 @@ impl GameState for State { match newrunstate { RunState::PreRun => { self.run_systems(); + self.ecs.maintain(); newrunstate = RunState::AwaitingInput; } RunState::AwaitingInput => { @@ -84,15 +88,33 @@ impl GameState for State { } RunState::PlayerTurn => { self.run_systems(); + self.ecs.maintain(); newrunstate = RunState::MonsterTurn; } RunState::MonsterTurn => { self.run_systems(); + self.ecs.maintain(); newrunstate = RunState::AwaitingInput; } RunState::ShowInventory => { - if gui::show_inventory(self, ctx) == gui::ItemMenuResult::Cancel { - newrunstate = RunState::AwaitingInput; + let result = gui::show_inventory(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::(), + WantsToDrinkPotion { + potion: item_entity, + }, + ) + .expect("failed to add intent to drink potion"); + + newrunstate = RunState::PlayerTurn; + } } } } @@ -145,6 +167,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();