Add ability to remove equipped items

This commit is contained in:
Timothy Warren 2021-11-15 11:32:09 -05:00
parent b2ed5e7758
commit a2ef1810d9
6 changed files with 156 additions and 3 deletions

View File

@ -175,3 +175,8 @@ pub struct MeleePowerBonus {
pub struct DefenseBonus {
pub defense: i32,
}
#[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct WantsToRemoveItem {
pub item: Entity,
}

View File

@ -1,5 +1,5 @@
use crate::components::{CombatStats, InBackpack, Name, Player, Position, Viewshed};
use crate::{game_log::GameLog, Map, RunState, State};
use crate::{game_log::GameLog, Equipped, Map, RunState, State};
use rltk::{Point, Rltk, VirtualKeyCode, RGB};
use specs::prelude::*;
@ -530,3 +530,92 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
selected: MainMenuSelection::NewGame,
}
}
pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entity>) {
let player_entity = gs.ecs.fetch::<Entity>();
let names = gs.ecs.read_storage::<Name>();
let backpack = gs.ecs.read_storage::<Equipped>();
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,
RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK),
);
ctx.print_color(
18,
y - 2,
RGB::named(rltk::YELLOW),
RGB::named(rltk::BLACK),
"Remove 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<Entity> = Vec::new();
let mut j = 0;
for (entity, _pack, name) in (&entities, &backpack, &names)
.join()
.filter(|item| item.1.owner == *player_entity)
{
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(21, y, &name.name.to_string());
equippable.push(entity);
y += 1;
j += 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)
}
},
}
}

View File

@ -319,3 +319,26 @@ impl<'a> System<'a> for ItemDropSystem {
wants_drop.clear();
}
}
pub struct ItemRemoveSystem {}
impl<'a> System<'a> for ItemRemoveSystem {
type SystemData = (
Entities<'a>,
WriteStorage<'a, WantsToRemoveItem>,
WriteStorage<'a, Equipped>,
WriteStorage<'a, InBackpack>
);
fn run(&mut self, data: Self::SystemData) {
let (entities, mut wants_remove, mut equipped, mut backpack) = data;
for (entity, to_remove) in (&entities, &wants_remove).join() {
equipped.remove(to_remove.item);
backpack.insert(to_remove.item, InBackpack { owner: entity})
.expect("Unable to remove item and put in backpack");
}
wants_remove.clear();
}
}

View File

@ -30,6 +30,7 @@ use monster_ai_system::MonsterAI;
use player::*;
pub use rect::Rect;
use visibility_system::VisibilitySystem;
use crate::inventory_system::ItemRemoveSystem;
/// Cut down on the amount of syntax to register components
macro_rules! register {
@ -61,6 +62,7 @@ pub enum RunState {
},
SaveGame,
NextLevel,
ShowRemoveItem,
}
pub struct State {
@ -97,6 +99,9 @@ impl State {
let mut drop_items = ItemDropSystem {};
drop_items.run_now(&self.ecs);
let mut item_remove = ItemRemoveSystem {};
item_remove.run_now(&self.ecs);
self.ecs.maintain();
}
}
@ -258,6 +263,25 @@ impl GameState for State {
self.goto_next_level();
newrunstate = RunState::PreRun;
}
RunState::ShowRemoveItem => {
let result = gui::remove_item_menu(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::<WantsToRemoveItem>();
intent
.insert(
*self.ecs.fetch::<Entity>(),
WantsToRemoveItem { item: item_entity },
)
.expect("Unable to insert intent to remove item");
newrunstate = RunState::PlayerTurn;
}
}
}
}
{
@ -405,6 +429,7 @@ fn main() -> rltk::BError {
Equipped,
MeleePowerBonus,
DefenseBonus,
WantsToRemoveItem,
);
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());

View File

@ -117,6 +117,9 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
// Skip Turn
VirtualKeyCode::Numpad5 | VirtualKeyCode::Space => return skip_turn(&mut gs.ecs),
// Remove item
VirtualKeyCode::R => return RunState::ShowRemoveItem,
_ => return RunState::AwaitingInput,
},
}

View File

@ -85,7 +85,11 @@ pub fn save_game(ecs: &mut World) {
WantsToUseItem,
WantsToDropItem,
SerializationHelper,
Equippable
Equippable,
Equipped,
MeleePowerBonus,
DefenseBonus,
WantsToRemoveItem
);
}
@ -147,7 +151,11 @@ pub fn load_game(ecs: &mut World) {
WantsToUseItem,
WantsToDropItem,
SerializationHelper,
Equippable
Equippable,
Equipped,
MeleePowerBonus,
DefenseBonus,
WantsToRemoveItem
);
}