diff --git a/src/components/serialize.rs b/src/components/serialize.rs index 68db97e..450366d 100644 --- a/src/components/serialize.rs +++ b/src/components/serialize.rs @@ -1,8 +1,9 @@ -use crate::map::{Map, MasterDungeonMap}; use ::serde::{Deserialize, Serialize}; use ::specs::prelude::*; use ::specs_derive::*; +use crate::map::{Map, MasterDungeonMap}; + // Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an // Entity. diff --git a/src/effects.rs b/src/effects.rs index 9c37a06..8b5058d 100644 --- a/src/effects.rs +++ b/src/effects.rs @@ -54,6 +54,7 @@ pub enum EffectType { } /// Who, or what the effect should affect. +#[allow(dead_code)] #[derive(Clone)] pub enum Targets { Single { target: Entity }, diff --git a/src/gui/menu.rs b/src/gui/menu.rs index 29a4892..046801d 100644 --- a/src/gui/menu.rs +++ b/src/gui/menu.rs @@ -1,9 +1,9 @@ -use ::rltk::{Rltk, VirtualKeyCode, RGB}; +use ::rltk::{FontCharType, Rltk, VirtualKeyCode, RGB}; use ::specs::prelude::*; use super::enums::*; use super::{get_item_color, get_item_display_name}; -use crate::components::{CursedItem, Equipped, InBackpack, Item, Name, Vendor}; +use crate::components::{CursedItem, Equipped, InBackpack, Item, Name, ObfuscatedName, Vendor}; use crate::rex_assets::RexAssets; use crate::{colors, MasterDungeonMap, RunState, State, VendorMode}; @@ -707,3 +707,108 @@ pub fn remove_curse_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opt }, } } + +pub fn identify_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option) { + use ::rltk::to_cp437; + + let player_entity = gs.ecs.fetch::(); + let equipped = gs.ecs.read_storage::(); + let backpack = gs.ecs.read_storage::(); + let entities = gs.ecs.entities(); + let items = gs.ecs.read_storage::(); + let names = gs.ecs.read_storage::(); + let dm = gs.ecs.fetch::(); + let obfuscated = gs.ecs.read_storage::(); + + let build_cursed_iterator = || { + (&entities, &items).join().filter(|(item_entity, _item)| { + let mut keep = false; + if let Some(bp) = backpack.get(*item_entity) { + if bp.owner == *player_entity { + if let Some(name) = names.get(*item_entity) { + if obfuscated.get(*item_entity).is_some() + && !dm.identified_items.contains(&name.name) + { + keep = true; + } + } + } + } + + // It's equipped, so we know it's cursed + if let Some(equip) = equipped.get(*item_entity) { + if equip.owner == *player_entity { + if let Some(name) = names.get(*item_entity) { + if obfuscated.get(*item_entity).is_some() + && !dm.identified_items.contains(&name.name) + { + keep = true; + } + } + } + } + + keep + }) + }; + + let count = build_cursed_iterator().count(); + + let mut y = (25 - (count / 2)) as i32; + ctx.draw_box( + 15, + y - 2, + 31, + (count + 3) as i32, + colors::WHITE, + colors::BLACK, + ); + ctx.print_color( + 18, + y - 2, + colors::YELLOW, + colors::BLACK, + "Identify Which Item?", + ); + ctx.print_color( + 18, + y + count as i32 + 1, + colors::YELLOW, + colors::BLACK, + "ESCAPE to cancel", + ); + + let mut equippable: Vec = Vec::new(); + for (j, (entity, _item)) in build_cursed_iterator().enumerate() { + ctx.set(17, y, colors::WHITE, colors::BLACK, to_cp437('(')); + ctx.set(18, y, colors::YELLOW, colors::BLACK, 97 + j as FontCharType); + ctx.set(19, y, colors::WHITE, colors::BLACK, to_cp437(')')); + + ctx.print_color( + 21, + y, + get_item_color(&gs.ecs, entity), + colors::BLACK, + &get_item_display_name(&gs.ecs, entity), + ); + equippable.push(entity); + y += 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/state.rs b/src/state.rs index d293302..5e7643d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -54,6 +54,7 @@ pub enum RunState { ShowVendor { vendor: Entity, mode: VendorMode }, TeleportingToOtherLevel { x: i32, y: i32, depth: i32 }, ShowRemoveCurse, + ShowIdentify, } pub struct State { @@ -267,6 +268,7 @@ impl GameState for State { RunState::TeleportingToOtherLevel { x, y, depth } } RunState::ShowRemoveCurse => RunState::ShowRemoveCurse, + RunState::ShowIdentify => RunState::ShowIdentify, _ => RunState::Ticking, }; } @@ -551,6 +553,22 @@ impl GameState for State { let item_entity = result.1.unwrap(); self.ecs.write_storage::().remove(item_entity); + newrunstate = RunState::Ticking; + } + } + } + RunState::ShowIdentify => { + let result = gui::identify_menu(self, ctx); + match result.0 { + gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput, + gui::ItemMenuResult::NoResponse => {} + gui::ItemMenuResult::Selected => { + let item_entity = result.1.unwrap(); + if let Some(name) = self.ecs.read_storage::().get(item_entity) { + let mut dm = self.ecs.fetch_mut::(); + dm.identified_items.insert(name.name.clone()); + } + newrunstate = RunState::Ticking; } }