Add ability to equip items

This commit is contained in:
Timothy Warren 2021-11-15 09:19:22 -05:00
parent f4f1800770
commit 4322b250cb
5 changed files with 128 additions and 9 deletions

View File

@ -148,3 +148,20 @@ pub struct SerializeMe;
pub struct SerializationHelper { pub struct SerializationHelper {
pub map: crate::map::Map, pub map: crate::map::Map,
} }
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
pub enum EquipmentSlot {
Melee,
Shield,
}
#[derive(Component, Serialize, Deserialize, Clone)]
pub struct Equippable {
pub slot: EquipmentSlot,
}
#[derive(Component, ConvertSaveload, Clone)]
pub struct Equipped {
pub owner: Entity,
pub slot: EquipmentSlot,
}

View File

@ -1,8 +1,5 @@
use crate::{ use crate::components::*;
game_log::GameLog, AreaOfEffect, CombatStats, Confusion, Consumable, InBackpack, use crate::{game_log::GameLog, Map};
InflictsDamage, Map, Name, Position, ProvidesHealing, SufferDamage, WantsToDropItem,
WantsToPickupItem, WantsToUseItem,
};
use specs::prelude::*; use specs::prelude::*;
pub struct ItemCollectionSystem {} pub struct ItemCollectionSystem {}
@ -63,6 +60,9 @@ impl<'a> System<'a> for ItemUseSystem {
WriteStorage<'a, SufferDamage>, WriteStorage<'a, SufferDamage>,
ReadStorage<'a, AreaOfEffect>, ReadStorage<'a, AreaOfEffect>,
WriteStorage<'a, Confusion>, WriteStorage<'a, Confusion>,
ReadStorage<'a, Equippable>,
WriteStorage<'a, Equipped>,
WriteStorage<'a, InBackpack>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
@ -80,6 +80,9 @@ impl<'a> System<'a> for ItemUseSystem {
mut suffer_damage, mut suffer_damage,
aoe, aoe,
mut confused, mut confused,
equippable,
mut equipped,
mut backpack,
) = data; ) = data;
for (entity, useitem) in (&entities, &wants_use).join() { for (entity, useitem) in (&entities, &wants_use).join() {
@ -119,6 +122,53 @@ impl<'a> System<'a> for ItemUseSystem {
} }
} }
// If it is equippable, then we want to equip it - and unequip whatever else was in that slot
match equippable.get(useitem.item) {
None => {}
Some(can_equip) => {
let target_slot = can_equip.slot;
let target = targets[0];
// Remove any items the target has in the item's slot
let mut to_unequip: Vec<Entity> = Vec::new();
for (item_entity, already_equipped, name) in
(&entities, &equipped, &names).join()
{
if already_equipped.owner == target && already_equipped.slot == target_slot
{
to_unequip.push(item_entity);
if target == *player_entity {
gamelog.entries.push(format!("You unequip {}.", name.name));
}
}
}
for item in to_unequip.iter() {
equipped.remove(*item);
backpack
.insert(*item, InBackpack { owner: target })
.expect("Unable to put unequipped item back in backpack");
}
// Wield the item
equipped
.insert(
useitem.item,
Equipped {
owner: target,
slot: target_slot,
},
)
.expect("Failed to equip item");
backpack.remove(useitem.item);
if target == *player_entity {
gamelog.entries.push(format!(
"You equip {}.",
names.get(useitem.item).unwrap().name
));
}
}
}
// If the item heals, apply the healing // If the item heals, apply the healing
match healing.get(useitem.item) { match healing.get(useitem.item) {
None => {} None => {}

View File

@ -275,6 +275,7 @@ impl State {
let player = self.ecs.read_storage::<Player>(); let player = self.ecs.read_storage::<Player>();
let backpack = self.ecs.read_storage::<InBackpack>(); let backpack = self.ecs.read_storage::<InBackpack>();
let player_entity = self.ecs.fetch::<Entity>(); let player_entity = self.ecs.fetch::<Entity>();
let equipped = self.ecs.read_storage::<Equipped>();
let mut to_delete: Vec<Entity> = Vec::new(); let mut to_delete: Vec<Entity> = Vec::new();
for entity in entities.join() { for entity in entities.join() {
@ -294,6 +295,13 @@ impl State {
} }
} }
let eq = equipped.get(entity);
if let Some(eq) = eq {
if eq.owner == *player_entity {
should_delete = false;
}
}
if should_delete { if should_delete {
to_delete.push(entity); to_delete.push(entity);
} }
@ -393,6 +401,7 @@ fn main() -> rltk::BError {
Confusion, Confusion,
SimpleMarker<SerializeMe>, SimpleMarker<SerializeMe>,
SerializationHelper, SerializationHelper,
Equippable,
); );
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new()); gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());

View File

@ -84,7 +84,8 @@ pub fn save_game(ecs: &mut World) {
WantsToPickupItem, WantsToPickupItem,
WantsToUseItem, WantsToUseItem,
WantsToDropItem, WantsToDropItem,
SerializationHelper SerializationHelper,
Equippable
); );
} }
@ -145,7 +146,8 @@ pub fn load_game(ecs: &mut World) {
WantsToPickupItem, WantsToPickupItem,
WantsToUseItem, WantsToUseItem,
WantsToDropItem, WantsToDropItem,
SerializationHelper SerializationHelper,
Equippable
); );
} }

View File

@ -1,6 +1,7 @@
use crate::components::{ use crate::components::{
AreaOfEffect, BlocksTile, CombatStats, Confusion, Consumable, InflictsDamage, Item, Monster, AreaOfEffect, BlocksTile, CombatStats, Confusion, Consumable, EquipmentSlot, Equippable,
Name, Player, Position, ProvidesHealing, Ranged, Renderable, SerializeMe, Viewshed, InflictsDamage, Item, Monster, Name, Player, Position, ProvidesHealing, Ranged, Renderable,
SerializeMe, Viewshed,
}; };
use crate::{random_table::RandomTable, Rect, MAP_WIDTH}; use crate::{random_table::RandomTable, Rect, MAP_WIDTH};
use rltk::{RandomNumberGenerator, RGB}; use rltk::{RandomNumberGenerator, RGB};
@ -44,6 +45,8 @@ fn room_table(map_depth: i32) -> RandomTable {
.add("Fireball Scroll", 2 + map_depth) .add("Fireball Scroll", 2 + map_depth)
.add("Confusion Scroll", 2 + map_depth) .add("Confusion Scroll", 2 + map_depth)
.add("Magic Missile Scroll", 4) .add("Magic Missile Scroll", 4)
.add("Dagger", 3)
.add("Shield", 3)
} }
/// fills a room with stuff! /// fills a room with stuff!
@ -88,6 +91,8 @@ pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32) {
"Fireball Scroll" => fireball_scroll(ecs, x, y), "Fireball Scroll" => fireball_scroll(ecs, x, y),
"Confusion Scroll" => confusion_scroll(ecs, x, y), "Confusion Scroll" => confusion_scroll(ecs, x, y),
"Magic Missile Scroll" => magic_missile_scroll(ecs, x, y), "Magic Missile Scroll" => magic_missile_scroll(ecs, x, y),
"Dagger" => dagger(ecs, x, y),
"Shield" => shield(ecs, x, y),
_ => {} _ => {}
} }
} }
@ -194,3 +199,39 @@ fn confusion_scroll(ecs: &mut World, x: i32, y: i32) {
.marked::<SimpleMarker<SerializeMe>>() .marked::<SimpleMarker<SerializeMe>>()
.build(); .build();
} }
fn dagger(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: rltk::to_cp437('/'),
fg: RGB::named(rltk::CYAN),
bg: RGB::named(rltk::BLACK),
render_order: 2,
})
.with(Name::new("Dagger"))
.with(Item {})
.with(Equippable {
slot: EquipmentSlot::Melee,
})
.marked::<SimpleMarker<SerializeMe>>()
.build();
}
fn shield(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: rltk::to_cp437('('),
fg: RGB::named(rltk::CYAN),
bg: RGB::named(rltk::BLACK),
render_order: 2,
})
.with(Name::new("Shield"))
.with(Item {})
.with(Equippable {
slot: EquipmentSlot::Shield,
})
.marked::<SimpleMarker<SerializeMe>>()
.build();
}