Add ability to drop items

This commit is contained in:
Timothy Warren 2021-11-04 09:40:58 -04:00
parent cfd2ed887a
commit e4be3b6855
5 changed files with 178 additions and 2 deletions

View File

@ -90,3 +90,8 @@ pub struct WantsToPickupItem {
pub struct WantsToDrinkPotion { pub struct WantsToDrinkPotion {
pub potion: Entity, pub potion: Entity,
} }
#[derive(Component, Debug, Clone)]
pub struct WantsToDropItem {
pub item: Entity,
}

View File

@ -247,3 +247,90 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option
}, },
} }
} }
pub fn drop_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::<InBackpack>();
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),
"Drop 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

@ -1,6 +1,6 @@
use crate::{ use crate::{
gamelog::GameLog, CombatStats, InBackpack, Name, Position, Potion, WantsToDrinkPotion, gamelog::GameLog, CombatStats, InBackpack, Name, Position, Potion, WantsToDrinkPotion,
WantsToPickupItem, WantsToDropItem, WantsToPickupItem,
}; };
use specs::prelude::*; use specs::prelude::*;
@ -91,3 +91,59 @@ impl<'a> System<'a> for PotionUseSystem {
wants_drink.clear(); wants_drink.clear();
} }
} }
pub struct ItemDropSystem {}
impl<'a> System<'a> for ItemDropSystem {
type SystemData = (
ReadExpect<'a, Entity>,
WriteExpect<'a, GameLog>,
Entities<'a>,
WriteStorage<'a, WantsToDropItem>,
ReadStorage<'a, Name>,
WriteStorage<'a, Position>,
WriteStorage<'a, InBackpack>,
);
fn run(&mut self, data: Self::SystemData) {
let (
player_entity,
mut gamelog,
entities,
mut wants_drop,
names,
mut positions,
mut backpack,
) = data;
for (entity, to_drop) in (&entities, &wants_drop).join() {
let mut dropper_pos: Position = Position { x: 0, y: 0 };
{
let dropped_pos = positions.get(entity).unwrap();
dropper_pos.x = dropped_pos.x;
dropper_pos.y = dropped_pos.y;
}
positions
.insert(
to_drop.item,
Position {
x: dropper_pos.x,
y: dropper_pos.y,
},
)
.expect("Unable to drop item to position");
backpack.remove(to_drop.item);
if entity == *player_entity {
gamelog.entries.push(format!(
"You drop the {}.",
names.get(to_drop.item).unwrap().name
));
}
}
wants_drop.clear();
}
}

View File

@ -18,7 +18,7 @@ mod visibility_system;
pub use components::*; pub use components::*;
use damage_system::DamageSystem; use damage_system::DamageSystem;
pub use gamelog::GameLog; pub use gamelog::GameLog;
use inventory_system::{ItemCollectionSystem, PotionUseSystem}; use inventory_system::{ItemCollectionSystem, ItemDropSystem, PotionUseSystem};
pub use map::*; pub use map::*;
use map_indexing_system::MapIndexingSystem; use map_indexing_system::MapIndexingSystem;
use melee_combat_system::MeleeCombatSystem; use melee_combat_system::MeleeCombatSystem;
@ -36,6 +36,7 @@ pub enum RunState {
PlayerTurn, PlayerTurn,
MonsterTurn, MonsterTurn,
ShowInventory, ShowInventory,
ShowDropItem,
} }
pub struct State { pub struct State {
@ -65,6 +66,9 @@ impl State {
let mut potions = PotionUseSystem {}; let mut potions = PotionUseSystem {};
potions.run_now(&self.ecs); potions.run_now(&self.ecs);
let mut drop_items = ItemDropSystem {};
drop_items.run_now(&self.ecs);
self.ecs.maintain(); self.ecs.maintain();
} }
} }
@ -118,6 +122,26 @@ impl GameState for State {
} }
} }
} }
RunState::ShowDropItem => {
let result = gui::drop_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::<WantsToDropItem>();
intent
.insert(
*self.ecs.fetch::<Entity>(),
WantsToDropItem { item: item_entity },
)
.expect("failed to add intent to drop item");
newrunstate = RunState::PlayerTurn;
}
}
}
} }
{ {
@ -169,6 +193,7 @@ fn main() -> rltk::BError {
gs.ecs.register::<InBackpack>(); gs.ecs.register::<InBackpack>();
gs.ecs.register::<WantsToPickupItem>(); gs.ecs.register::<WantsToPickupItem>();
gs.ecs.register::<WantsToDrinkPotion>(); gs.ecs.register::<WantsToDrinkPotion>();
gs.ecs.register::<WantsToDropItem>();
let map: Map = Map::new_map_rooms_and_corridors(); let map: Map = Map::new_map_rooms_and_corridors();
let (player_x, player_y) = map.rooms[0].center(); let (player_x, player_y) = map.rooms[0].center();

View File

@ -101,6 +101,9 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
// Show inventory // Show inventory
VirtualKeyCode::I => return RunState::ShowInventory, VirtualKeyCode::I => return RunState::ShowInventory,
// Show item drop screen
VirtualKeyCode::D => return RunState::ShowDropItem,
_ => return RunState::AwaitingInput, _ => return RunState::AwaitingInput,
}, },
} }