From b4420ba5383645ffcca2f9dc6aa49b68a6175a84 Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Sun, 23 Jul 2023 01:42:26 +0100 Subject: [PATCH] inventory refactor, maybe slightly unwieldy --- src/gui.rs | 61 +++++++++++++++++++++++++++++++--------- src/inventory_system.rs | 1 - src/main.rs | 6 ++-- src/spawner.rs | 2 +- src/visibility_system.rs | 3 -- 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/gui.rs b/src/gui.rs index 7472c63..4960efc 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -4,6 +4,7 @@ use super::{ }; use rltk::{Rltk, VirtualKeyCode, RGB}; use specs::prelude::*; +use std::collections::BTreeMap; pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { ctx.draw_hollow_box_double(0, 43, 79, 7, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK)); @@ -141,23 +142,40 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option 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(); + // FIXME: This is unwieldy. Having a separate data structure for (items, id) and (items, count) is not good. + // But it works, and this might get cut anyway as I get further along in the design, so leaving as is atm. + let mut inventory_ids: BTreeMap = BTreeMap::new(); + let mut player_inventory: BTreeMap = BTreeMap::new(); + for (entity, _pack, name) in (&entities, &backpack, &names).join().filter(|item| item.1.owner == *player_entity) { + player_inventory.entry(name.name.to_string()).and_modify(|count| *count += 1).or_insert(1); + inventory_ids.entry(name.name.to_string()).or_insert(entity); + } + let count = player_inventory.len(); let mut y = (25 - (count / 2)) as i32; ctx.draw_box(15, y - 2, 37, (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), "Inventory"); ctx.print_color(18, y + count as i32 + 1, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "ESC 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) { + for (name, item_count) in &player_inventory { 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(')')); + let mut x = 21; - ctx.print(21, y, &name.name.to_string()); - equippable.push(entity); + let vowels = ['a', 'e', 'i', 'o', 'u']; + if item_count > &1 { + ctx.print(x, y, item_count); + x += 2; + } else if vowels.iter().any(|&v| name.starts_with(v)) { + ctx.print(x, y, "an"); + x += 3; + } else { + ctx.print(x, y, "a"); + x += 2; + } + ctx.print(x, y, name.to_string()); y += 1; j += 1; } @@ -169,7 +187,7 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option _ => { let selection = rltk::letter_to_option(key); if selection > -1 && selection < count as i32 { - return (ItemMenuResult::Selected, Some(equippable[selection as usize])); + return (ItemMenuResult::Selected, Some(*inventory_ids.iter().nth(selection as usize).unwrap().1)); } (ItemMenuResult::NoResponse, None) } @@ -183,23 +201,38 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option 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 inventory_ids: BTreeMap = BTreeMap::new(); + let mut player_inventory: BTreeMap = BTreeMap::new(); + for (entity, _pack, name) in (&entities, &backpack, &names).join().filter(|item| item.1.owner == *player_entity) { + player_inventory.entry(name.name.to_string()).and_modify(|count| *count += 1).or_insert(1); + inventory_ids.entry(name.name.to_string()).or_insert(entity); + } + let count = player_inventory.len(); let mut y = (25 - (count / 2)) as i32; ctx.draw_box(15, y - 2, 37, (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 what?"); ctx.print_color(18, y + count as i32 + 1, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "ESC 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) { + for (name, item_count) in &player_inventory { 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(')')); + let mut x = 21; - ctx.print(21, y, &name.name.to_string()); - equippable.push(entity); + let vowels = ['a', 'e', 'i', 'o', 'u']; + if item_count > &1 { + ctx.print(x, y, item_count); + x += 2; + } else if vowels.iter().any(|&v| name.starts_with(v)) { + ctx.print(x, y, "an"); + x += 3; + } else { + ctx.print(x, y, "a"); + x += 2; + } + ctx.print(x, y, name.to_string()); y += 1; j += 1; } @@ -211,7 +244,7 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option _ => { let selection = rltk::letter_to_option(key); if selection > -1 && selection < count as i32 { - return (ItemMenuResult::Selected, Some(equippable[selection as usize])); + return (ItemMenuResult::Selected, Some(*inventory_ids.iter().nth(selection as usize).unwrap().1)); } (ItemMenuResult::NoResponse, None) } diff --git a/src/inventory_system.rs b/src/inventory_system.rs index c34bba7..b8c13e2 100644 --- a/src/inventory_system.rs +++ b/src/inventory_system.rs @@ -203,7 +203,6 @@ impl<'a> System<'a> for ItemUseSystem { if let Some(hc) = hc { hc.state = HungerState::Satiated; hc.duration = 50; - gamelog::Logger::new().append("You eat the").item_name_n(&item_being_used.name).period().log(); } } } diff --git a/src/main.rs b/src/main.rs index 22fd2f4..485b8f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,16 +132,16 @@ impl State { let mut particle_system = particle_system::ParticleSpawnSystem {}; vis.run_now(&self.ecs); + hunger_clock.run_now(&self.ecs); mob.run_now(&self.ecs); mapindex.run_now(&self.ecs); trigger_system.run_now(&self.ecs); - melee_system.run_now(&self.ecs); - damage_system.run_now(&self.ecs); inventory_system.run_now(&self.ecs); item_use_system.run_now(&self.ecs); item_drop_system.run_now(&self.ecs); item_remove_system.run_now(&self.ecs); - hunger_clock.run_now(&self.ecs); + melee_system.run_now(&self.ecs); + damage_system.run_now(&self.ecs); particle_system.run_now(&self.ecs); self.ecs.maintain(); diff --git a/src/spawner.rs b/src/spawner.rs index f7ea8a0..ebd226c 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -78,7 +78,7 @@ pub fn roll_hit_dice(ecs: &mut World, n: i32, d: i32) -> i32 { } // Consts -const MAX_ENTITIES: i32 = 2; +const MAX_ENTITIES: i32 = 4; /// Fills a room with stuff! pub fn spawn_room( diff --git a/src/visibility_system.rs b/src/visibility_system.rs index 626ef3f..ace0826 100644 --- a/src/visibility_system.rs +++ b/src/visibility_system.rs @@ -23,9 +23,6 @@ impl<'a> System<'a> for VisibilitySystem { for (ent, viewshed, pos) in (&entities, &mut viewshed, &pos).join() { if viewshed.dirty { viewshed.dirty = false; - // FIXME: SymmetricShadowcasting seems to be responsible for an infrequent crash -- - // but it could be unrelated to the FieldOfViewAlg being used. Needs some more testing! - // Appeared first after switching, but can't seem to reproduce it. let origin = Point::new(pos.x, pos.y); viewshed.visible_tiles = SymmetricShadowcasting.field_of_view(origin, viewshed.range, &*map); viewshed.visible_tiles.retain(|p| {