inventory refactor, maybe slightly unwieldy

This commit is contained in:
Llywelwyn 2023-07-23 01:42:26 +01:00
parent e2afd47830
commit b4420ba538
5 changed files with 51 additions and 22 deletions

View file

@ -4,6 +4,7 @@ use super::{
}; };
use rltk::{Rltk, VirtualKeyCode, RGB}; use rltk::{Rltk, VirtualKeyCode, RGB};
use specs::prelude::*; use specs::prelude::*;
use std::collections::BTreeMap;
pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { 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)); 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::<InBackpack>(); let backpack = gs.ecs.read_storage::<InBackpack>();
let entities = gs.ecs.entities(); let entities = gs.ecs.entities();
let inventory = (&backpack, &names).join().filter(|item| item.0.owner == *player_entity); // FIXME: This is unwieldy. Having a separate data structure for (items, id) and (items, count) is not good.
let count = inventory.count(); // 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<String, Entity> = BTreeMap::new();
let mut player_inventory: BTreeMap<String, i32> = 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; 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.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 - 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"); ctx.print_color(18, y + count as i32 + 1, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "ESC to cancel");
let mut equippable: Vec<Entity> = Vec::new();
let mut j = 0; 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(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(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.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()); let vowels = ['a', 'e', 'i', 'o', 'u'];
equippable.push(entity); 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; y += 1;
j += 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); let selection = rltk::letter_to_option(key);
if selection > -1 && selection < count as i32 { 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) (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::<InBackpack>(); let backpack = gs.ecs.read_storage::<InBackpack>();
let entities = gs.ecs.entities(); let entities = gs.ecs.entities();
let inventory = (&backpack, &names).join().filter(|item| item.0.owner == *player_entity); let mut inventory_ids: BTreeMap<String, Entity> = BTreeMap::new();
let count = inventory.count(); let mut player_inventory: BTreeMap<String, i32> = 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; 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.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 - 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"); ctx.print_color(18, y + count as i32 + 1, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "ESC to cancel");
let mut equippable: Vec<Entity> = Vec::new();
let mut j = 0; 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(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(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.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()); let vowels = ['a', 'e', 'i', 'o', 'u'];
equippable.push(entity); 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; y += 1;
j += 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); let selection = rltk::letter_to_option(key);
if selection > -1 && selection < count as i32 { 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) (ItemMenuResult::NoResponse, None)
} }

View file

@ -203,7 +203,6 @@ impl<'a> System<'a> for ItemUseSystem {
if let Some(hc) = hc { if let Some(hc) = hc {
hc.state = HungerState::Satiated; hc.state = HungerState::Satiated;
hc.duration = 50; hc.duration = 50;
gamelog::Logger::new().append("You eat the").item_name_n(&item_being_used.name).period().log();
} }
} }
} }

View file

@ -132,16 +132,16 @@ impl State {
let mut particle_system = particle_system::ParticleSpawnSystem {}; let mut particle_system = particle_system::ParticleSpawnSystem {};
vis.run_now(&self.ecs); vis.run_now(&self.ecs);
hunger_clock.run_now(&self.ecs);
mob.run_now(&self.ecs); mob.run_now(&self.ecs);
mapindex.run_now(&self.ecs); mapindex.run_now(&self.ecs);
trigger_system.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); inventory_system.run_now(&self.ecs);
item_use_system.run_now(&self.ecs); item_use_system.run_now(&self.ecs);
item_drop_system.run_now(&self.ecs); item_drop_system.run_now(&self.ecs);
item_remove_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); particle_system.run_now(&self.ecs);
self.ecs.maintain(); self.ecs.maintain();

View file

@ -78,7 +78,7 @@ pub fn roll_hit_dice(ecs: &mut World, n: i32, d: i32) -> i32 {
} }
// Consts // Consts
const MAX_ENTITIES: i32 = 2; const MAX_ENTITIES: i32 = 4;
/// Fills a room with stuff! /// Fills a room with stuff!
pub fn spawn_room( pub fn spawn_room(

View file

@ -23,9 +23,6 @@ impl<'a> System<'a> for VisibilitySystem {
for (ent, viewshed, pos) in (&entities, &mut viewshed, &pos).join() { for (ent, viewshed, pos) in (&entities, &mut viewshed, &pos).join() {
if viewshed.dirty { if viewshed.dirty {
viewshed.dirty = false; 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); let origin = Point::new(pos.x, pos.y);
viewshed.visible_tiles = SymmetricShadowcasting.field_of_view(origin, viewshed.range, &*map); viewshed.visible_tiles = SymmetricShadowcasting.field_of_view(origin, viewshed.range, &*map);
viewshed.visible_tiles.retain(|p| { viewshed.visible_tiles.retain(|p| {