From f096aa36e985fe77b30d0c219e78d606dabd6dc0 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Wed, 2 Feb 2022 11:52:19 -0500 Subject: [PATCH] Refactor item-related menus --- src/gui.rs | 4 +- src/gui/cheat_menu.rs | 54 ++++++-------- src/gui/drop_item_menu.rs | 92 ++++++----------------- src/gui/enums.rs | 6 -- src/gui/identify_menu.rs | 85 +++++---------------- src/gui/inventory_menu.rs | 86 ++++----------------- src/gui/menus.rs | 100 +++++++++++++++++++++++++ src/gui/ranged_target.rs | 2 +- src/gui/remove_curse_menu.rs | 141 ++++++++++------------------------- src/gui/remove_item_menu.rs | 100 ++++++------------------- 10 files changed, 245 insertions(+), 425 deletions(-) delete mode 100644 src/gui/enums.rs create mode 100644 src/gui/menus.rs diff --git a/src/gui.rs b/src/gui.rs index a81b180..eccdb26 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,13 +1,13 @@ //! Interface-building output mod cheat_menu; mod drop_item_menu; -mod enums; mod game_over_menu; mod hud; mod identify_menu; mod inventory_menu; mod item_render; mod main_menu; +mod menus; mod ranged_target; mod remove_curse_menu; mod remove_item_menu; @@ -16,13 +16,13 @@ mod vendor_menu; pub use cheat_menu::*; pub use drop_item_menu::*; -pub use enums::*; pub use game_over_menu::*; pub use hud::*; pub use identify_menu::*; pub use inventory_menu::*; pub use item_render::*; pub use main_menu::*; +pub use menus::*; pub use ranged_target::*; pub use remove_curse_menu::*; pub use remove_item_menu::*; diff --git a/src/gui/cheat_menu.rs b/src/gui/cheat_menu.rs index 22876d0..8d7d710 100644 --- a/src/gui/cheat_menu.rs +++ b/src/gui/cheat_menu.rs @@ -1,5 +1,7 @@ +use ::rltk::prelude::*; use ::rltk::{Rltk, VirtualKeyCode}; +use super::{menu_box, menu_option}; use crate::{colors, State}; #[derive(PartialEq, Copy, Clone)] @@ -13,48 +15,36 @@ pub enum CheatMenuResult { } pub fn show_cheat_mode(_gs: &mut State, ctx: &mut Rltk) -> CheatMenuResult { + let mut draw_batch = DrawBatch::new(); let count = 4; 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, "Cheating!"); - ctx.print_color( - 18, - y + count as i32 + 1, - colors::YELLOW, - colors::BLACK, + menu_box(&mut draw_batch, 15, y, (count + 3) as i32, "Cheating!"); + draw_batch.print_color( + Point::new(18, y + count as i32 + 1), "ESCAPE to cancel", + ColorPair::new(colors::YELLOW, colors::BLACK), ); - ctx.set(17, y, colors::WHITE, colors::BLACK, rltk::to_cp437('(')); - ctx.set(18, y, colors::YELLOW, colors::BLACK, rltk::to_cp437('T')); - ctx.set(19, y, colors::WHITE, colors::BLACK, rltk::to_cp437(')')); - - ctx.print(21, y, "Teleport to next level"); - + menu_option( + &mut draw_batch, + 17, + y, + to_cp437('T'), + "Teleport to next level", + ); y += 1; - ctx.set(17, y, colors::WHITE, colors::BLACK, rltk::to_cp437('(')); - ctx.set(18, y, colors::YELLOW, colors::BLACK, rltk::to_cp437('H')); - ctx.set(19, y, colors::WHITE, colors::BLACK, rltk::to_cp437(')')); - ctx.print(21, y, "Heal all wounds"); + menu_option(&mut draw_batch, 17, y, to_cp437('H'), "Heal all wounds"); y += 1; - ctx.set(17, y, colors::WHITE, colors::BLACK, rltk::to_cp437('(')); - ctx.set(18, y, colors::YELLOW, colors::BLACK, rltk::to_cp437('R')); - ctx.set(19, y, colors::WHITE, colors::BLACK, rltk::to_cp437(')')); - ctx.print(21, y, "Reveal the map"); + menu_option(&mut draw_batch, 17, y, to_cp437('R'), "Reveal the map"); y += 1; - ctx.set(17, y, colors::WHITE, colors::BLACK, rltk::to_cp437('(')); - ctx.set(18, y, colors::YELLOW, colors::BLACK, rltk::to_cp437('G')); - ctx.set(19, y, colors::WHITE, colors::BLACK, rltk::to_cp437(')')); - ctx.print(21, y, "God Mode (No Death)"); + + menu_option(&mut draw_batch, 17, y, to_cp437('G'), "God Mode (No Death)"); + + draw_batch + .submit(6000) + .expect("Failed to batch draw cheat menu"); match ctx.key { None => CheatMenuResult::NoResponse, diff --git a/src/gui/drop_item_menu.rs b/src/gui/drop_item_menu.rs index c741026..c7cf2e9 100644 --- a/src/gui/drop_item_menu.rs +++ b/src/gui/drop_item_menu.rs @@ -1,83 +1,35 @@ -use ::rltk::{Rltk, VirtualKeyCode}; +use ::rltk::prelude::*; +use ::rltk::Rltk; use ::specs::prelude::*; -use super::enums::*; -use super::{get_item_color, get_item_display_name}; -use crate::components::{InBackpack, Name}; -use crate::{colors, State}; +use super::{get_item_display_name, item_result_menu, ItemMenuResult}; +use crate::components::InBackpack; +use crate::State; pub fn drop_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option) { + let mut draw_batch = DrawBatch::new(); + 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, - colors::WHITE, - colors::BLACK, - ); - ctx.print_color(18, y - 2, colors::YELLOW, colors::BLACK, "Drop Which Item?"); - ctx.print_color( - 18, - y + count as i32 + 1, - colors::YELLOW, - colors::BLACK, - "ESCAPE to cancel", - ); - - let mut equippable: Vec = Vec::new(); - let mut j = 0; - #[allow(clippy::explicit_counter_loop)] - for (entity, _pack) in (&entities, &backpack) + let mut items: Vec<(Entity, String)> = Vec::new(); + (&entities, &backpack) .join() .filter(|item| item.1.owner == *player_entity) - { - ctx.set(17, y, colors::WHITE, colors::BLACK, rltk::to_cp437('(')); - ctx.set( - 18, - y, - colors::YELLOW, - colors::BLACK, - 97 + j as rltk::FontCharType, - ); - ctx.set(19, y, colors::WHITE, colors::BLACK, rltk::to_cp437(')')); + .for_each(|item| items.push((item.0, get_item_display_name(&gs.ecs, item.0)))); - 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; - j += 1; - } + let result = item_result_menu( + &mut draw_batch, + "Drop which item?", + items.len(), + &items, + ctx.key, + ); - 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) - } - }, - } + draw_batch + .submit(6000) + .expect("Failed to batch render Drop Item Menu"); + + result } diff --git a/src/gui/enums.rs b/src/gui/enums.rs deleted file mode 100644 index 71c2330..0000000 --- a/src/gui/enums.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[derive(PartialEq, Copy, Clone)] -pub enum ItemMenuResult { - Cancel, - NoResponse, - Selected, -} diff --git a/src/gui/identify_menu.rs b/src/gui/identify_menu.rs index 9404bb8..37197a1 100644 --- a/src/gui/identify_menu.rs +++ b/src/gui/identify_menu.rs @@ -1,25 +1,27 @@ -use ::rltk::{FontCharType, Rltk, VirtualKeyCode}; +use ::rltk::prelude::*; +use ::rltk::Rltk; use ::specs::prelude::*; -use super::enums::*; -use super::{get_item_color, get_item_display_name}; +use super::{get_item_display_name, item_result_menu, ItemMenuResult}; use crate::components::{Equipped, InBackpack, Item, Name, ObfuscatedName}; -use crate::{colors, MasterDungeonMap, State}; +use crate::{MasterDungeonMap, State}; pub fn identify_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option) { - use ::rltk::to_cp437; + let mut draw_batch = DrawBatch::new(); 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 item_components = 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 items: Vec<(Entity, String)> = Vec::new(); + (&entities, &item_components) + .join() + .filter(|(item_entity, _item)| { let mut keep = false; if let Some(bp) = backpack.get(*item_entity) { if bp.owner == *player_entity { @@ -48,65 +50,18 @@ pub fn identify_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option< keep }) - }; + .for_each(|item| items.push((item.0, get_item_display_name(&gs.ecs, item.0)))); - 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, + let result = item_result_menu( + &mut draw_batch, "Identify Which Item?", + items.len(), + &items, + ctx.key, ); - ctx.print_color( - 18, - y + count as i32 + 1, - colors::YELLOW, - colors::BLACK, - "ESCAPE to cancel", - ); + draw_batch + .submit(6000) + .expect("Failed to batch render Identify menu"); - 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) - } - }, - } + result } diff --git a/src/gui/inventory_menu.rs b/src/gui/inventory_menu.rs index e4ef196..d8f9dca 100644 --- a/src/gui/inventory_menu.rs +++ b/src/gui/inventory_menu.rs @@ -1,83 +1,29 @@ -use ::rltk::{Rltk, VirtualKeyCode}; +use ::rltk::prelude::*; +use ::rltk::Rltk; use ::specs::prelude::*; -use super::enums::*; -use super::{get_item_color, get_item_display_name}; -use crate::components::{InBackpack, Name}; -use crate::{colors, State}; +use super::{get_item_display_name, item_result_menu, ItemMenuResult}; +use crate::components::InBackpack; +use crate::State; pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option) { + let mut draw_batch = DrawBatch::new(); + 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, - colors::WHITE, - colors::BLACK, - ); - ctx.print_color(18, y - 2, colors::YELLOW, colors::BLACK, "Inventory"); - ctx.print_color( - 18, - y + count as i32 + 1, - colors::YELLOW, - colors::BLACK, - "ESCAPE to cancel", - ); - - let mut equippable: Vec = Vec::new(); - let mut j = 0; - #[allow(clippy::explicit_counter_loop)] - for (entity, _pack) in (&entities, &backpack) + let mut items: Vec<(Entity, String)> = Vec::new(); + (&entities, &backpack) .join() .filter(|item| item.1.owner == *player_entity) - { - ctx.set(17, y, colors::WHITE, colors::BLACK, rltk::to_cp437('(')); - ctx.set( - 18, - y, - colors::YELLOW, - colors::BLACK, - 97 + j as rltk::FontCharType, - ); - ctx.set(19, y, colors::WHITE, colors::BLACK, rltk::to_cp437(')')); + .for_each(|item| items.push((item.0, get_item_display_name(&gs.ecs, item.0)))); - 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; - j += 1; - } + let result = item_result_menu(&mut draw_batch, "Inventory", items.len(), &items, ctx.key); - 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) - } - }, - } + draw_batch + .submit(6000) + .expect("Failed to batch render Inventory Menu"); + + result } diff --git a/src/gui/menus.rs b/src/gui/menus.rs new file mode 100644 index 0000000..90535f9 --- /dev/null +++ b/src/gui/menus.rs @@ -0,0 +1,100 @@ +use ::rltk::prelude::*; +use ::specs::prelude::*; + +use crate::colors; + +#[derive(PartialEq, Copy, Clone)] +pub enum ItemMenuResult { + Cancel, + NoResponse, + Selected, +} + +pub fn menu_box(draw_batch: &mut DrawBatch, x: i32, y: i32, width: i32, title: T) { + draw_batch.draw_box( + Rect::with_size(x, y - 2, 31, width), + ColorPair::new(colors::WHITE, colors::BLACK), + ); + draw_batch.print_color( + Point::new(18, y - 2), + &title.to_string(), + ColorPair::new(colors::MAGENTA, colors::BLACK), + ); +} + +pub fn menu_option( + draw_batch: &mut DrawBatch, + x: i32, + y: i32, + hotkey: ::rltk::FontCharType, + text: T, +) { + draw_batch.set( + Point::new(x, y), + ColorPair::new(colors::WHITE, colors::BLACK), + to_cp437('('), + ); + draw_batch.set( + Point::new(x + 1, y), + ColorPair::new(colors::YELLOW, colors::BLACK), + hotkey, + ); + draw_batch.set( + Point::new(x + 2, y), + ColorPair::new(colors::WHITE, colors::BLACK), + to_cp437(')'), + ); + draw_batch.print_color( + Point::new(x + 5, y), + &text.to_string(), + ColorPair::new(colors::YELLOW, colors::BLACK), + ); +} + +pub fn item_result_menu( + draw_batch: &mut DrawBatch, + title: S, + count: usize, + items: &[(Entity, String)], + key: Option, +) -> (ItemMenuResult, Option) { + let mut y = (25 - (count / 2)) as i32; + draw_batch.draw_box( + Rect::with_size(15, y - 2, 31, (count + 3) as i32), + ColorPair::new(colors::WHITE, colors::BLACK), + ); + draw_batch.print_color( + Point::new(18, y - 2), + &title.to_string(), + ColorPair::new(colors::YELLOW, colors::BLACK), + ); + draw_batch.print_color( + Point::new(18, y + count as i32 + 1), + "ESCAPE to cancel", + ColorPair::new(colors::YELLOW, colors::BLACK), + ); + + let mut item_list: Vec = Vec::new(); + for (j, item) in items.iter().enumerate() { + menu_option(draw_batch, 17, y, 97 + j as FontCharType, &item.1); + item_list.push(item.0); + y += 1; + } + + match 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(item_list[selection as usize]), + ); + } + (ItemMenuResult::NoResponse, None) + } + }, + } +} diff --git a/src/gui/ranged_target.rs b/src/gui/ranged_target.rs index 4eb10ca..71beb09 100644 --- a/src/gui/ranged_target.rs +++ b/src/gui/ranged_target.rs @@ -1,7 +1,7 @@ use ::rltk::{DistanceAlg, Point, Rltk}; use ::specs::prelude::*; -use super::enums::*; +use super::ItemMenuResult; use crate::components::Viewshed; use crate::{camera, colors, State}; diff --git a/src/gui/remove_curse_menu.rs b/src/gui/remove_curse_menu.rs index 160da0d..fd38687 100644 --- a/src/gui/remove_curse_menu.rs +++ b/src/gui/remove_curse_menu.rs @@ -1,8 +1,8 @@ -use ::rltk::{Rltk, VirtualKeyCode, RGB}; +use ::rltk::prelude::*; +use ::rltk::Rltk; use ::specs::prelude::*; -use super::enums::*; -use super::{get_item_color, get_item_display_name}; +use super::{get_item_display_name, item_result_menu, ItemMenuResult}; use crate::components::{CursedItem, Equipped, InBackpack, Item, Name}; use crate::{MasterDungeonMap, State}; @@ -11,110 +11,49 @@ pub fn remove_curse_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opt let equipped = gs.ecs.read_storage::(); let backpack = gs.ecs.read_storage::(); let entities = gs.ecs.entities(); - let items = gs.ecs.read_storage::(); + let item_components = gs.ecs.read_storage::(); let cursed = gs.ecs.read_storage::(); let names = gs.ecs.read_storage::(); let dm = gs.ecs.fetch::(); - let build_cursed_iterator = || { - (&entities, &items, &cursed) - .join() - .filter(|(item_entity, _item, _cursed)| { - 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 dm.identified_items.contains(&name.name) { - keep = true; - } + let mut draw_batch = DrawBatch::new(); + + let mut items = Vec::new(); + + (&entities, &item_components, &cursed) + .join() + .filter(|(item_entity, _item, _cursed)| { + 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 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 { - 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, - RGB::named(rltk::WHITE), - RGB::named(rltk::BLACK), - ); - ctx.print_color( - 18, - y - 2, - RGB::named(rltk::YELLOW), - RGB::named(rltk::BLACK), - "Remove Curse From 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(); - for (j, (entity, _item, _cursed)) in build_cursed_iterator().enumerate() { - 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_color( - 21, - y, - get_item_color(&gs.ecs, entity), - RGB::from_f32(0.0, 0.0, 0.0), - &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) } - }, - } + // It's equipped, so we know it's cursed + if let Some(equip) = equipped.get(*item_entity) { + if equip.owner == *player_entity { + keep = true; + } + } + keep + }) + .for_each(|item| items.push((item.0, get_item_display_name(&gs.ecs, item.0)))); + + let result = item_result_menu( + &mut draw_batch, + "Remove Curse From Which Item?", + items.len(), + &items, + ctx.key, + ); + + draw_batch + .submit(6000) + .expect("Failed to batch render Remove Curse Menu"); + + result } diff --git a/src/gui/remove_item_menu.rs b/src/gui/remove_item_menu.rs index 79fb2b5..8fd446c 100644 --- a/src/gui/remove_item_menu.rs +++ b/src/gui/remove_item_menu.rs @@ -1,91 +1,35 @@ -use ::rltk::{Rltk, VirtualKeyCode}; +use ::rltk::prelude::*; +use ::rltk::Rltk; use ::specs::prelude::*; -use super::enums::*; -use super::{get_item_color, get_item_display_name}; -use crate::components::{Equipped, Name}; -use crate::{colors, State}; +use super::{get_item_display_name, item_result_menu, ItemMenuResult}; +use crate::components::InBackpack; +use crate::State; pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option) { + let mut draw_batch = DrawBatch::new(); + let player_entity = gs.ecs.fetch::(); - let names = gs.ecs.read_storage::(); - let backpack = 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, - colors::WHITE, - colors::BLACK, - ); - ctx.print_color( - 18, - y - 2, - colors::YELLOW, - colors::BLACK, - "Remove Which Item?", - ); - ctx.print_color( - 18, - y + count as i32 + 1, - colors::YELLOW, - colors::BLACK, - "ESCAPE to cancel", - ); - - let mut equippable: Vec = Vec::new(); - let mut j = 0; - #[allow(clippy::explicit_counter_loop)] - for (entity, _pack) in (&entities, &backpack) + let mut items: Vec<(Entity, String)> = Vec::new(); + (&entities, &backpack) .join() .filter(|item| item.1.owner == *player_entity) - { - ctx.set(17, y, colors::WHITE, colors::BLACK, rltk::to_cp437('(')); - ctx.set( - 18, - y, - colors::YELLOW, - colors::BLACK, - 97 + j as rltk::FontCharType, - ); - ctx.set(19, y, colors::WHITE, colors::BLACK, rltk::to_cp437(')')); + .for_each(|item| items.push((item.0, get_item_display_name(&gs.ecs, item.0)))); - ctx.print_color( - 21, - y, - get_item_color(&gs.ecs, entity), - colors::BLACK, - &get_item_display_name(&gs.ecs, entity), - ); + let result = item_result_menu( + &mut draw_batch, + "Remove which item?", + items.len(), + &items, + ctx.key, + ); - equippable.push(entity); - y += 1; - j += 1; - } + draw_batch + .submit(6000) + .expect("Failed to batch render Remove Item Menu"); - 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) - } - }, - } + result }