diff --git a/src/gui/mod.rs b/src/gui/mod.rs index b6b52f2..9baa021 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -4,7 +4,7 @@ use super::{ Name, ObfuscatedName, Player, Point, Pools, Position, Prop, Renderable, RunState, Skill, Skills, State, Viewshed, Wand, }; -use rltk::{Rltk, VirtualKeyCode, RGB}; +use rltk::prelude::*; use specs::prelude::*; use std::collections::BTreeMap; mod cheat_menu; @@ -472,6 +472,33 @@ pub fn get_item_colour(ecs: &World, item: Entity) -> RGB { return RGB::named(rltk::WHITE); } +pub fn item_colour_u8( + item: Entity, + names: &ReadStorage, + magic_items: &ReadStorage, + dm: &MasterDungeonMap, +) -> (u8, u8, u8) { + if let Some(name) = names.get(item) { + if let Some(magic) = magic_items.get(item) { + if dm.identified_items.contains(&name.name) { + // If identified magic item, use rarity colour + match magic.class { + MagicItemClass::Common => return WHITE, + MagicItemClass::Uncommon => return GREEN, + MagicItemClass::Rare => return BLUE, + MagicItemClass::VeryRare => return PURPLE, + MagicItemClass::Legendary => return GOLD, + } + } else { + // Unidentified magic item + return GREY; + } + } + } + // If nonmagic, just use white + return WHITE; +} + pub fn show_help(ctx: &mut Rltk) -> YesNoResult { let mut x = 3; let mut y = 12; diff --git a/src/inventory/equip_system.rs b/src/inventory/equip_system.rs new file mode 100644 index 0000000..d4c53f3 --- /dev/null +++ b/src/inventory/equip_system.rs @@ -0,0 +1,91 @@ +use super::{ + gamelog, EquipmentChanged, Equippable, Equipped, InBackpack, MagicItem, MasterDungeonMap, Name, ObfuscatedName, + WantsToUseItem, +}; +use crate::gui::{item_colour_u8, obfuscate_name}; +use specs::prelude::*; + +pub struct ItemEquipSystem {} + +impl<'a> System<'a> for ItemEquipSystem { + #[allow(clippy::type_complexity)] + type SystemData = ( + ReadExpect<'a, Entity>, + Entities<'a>, + WriteStorage<'a, WantsToUseItem>, + ReadStorage<'a, Name>, + ReadStorage<'a, Equippable>, + WriteStorage<'a, Equipped>, + WriteStorage<'a, InBackpack>, + WriteStorage<'a, EquipmentChanged>, + ReadStorage<'a, MagicItem>, + ReadStorage<'a, ObfuscatedName>, + ReadExpect<'a, MasterDungeonMap>, + ); + + #[allow(clippy::cognitive_complexity)] + fn run(&mut self, data: Self::SystemData) { + let ( + player_entity, + entities, + mut wants_to_use_item, + names, + equippable, + mut equipped, + mut backpack, + mut dirty, + magic_items, + obfuscated_names, + dm, + ) = data; + let mut remove: Vec = Vec::new(); + // For every item with a target, if the item is equippable, find the correct slot. + for (target, wants_to_use_item) in (&entities, &wants_to_use_item).join() { + if let Some(can_equip) = equippable.get(wants_to_use_item.item) { + let target_slot = can_equip.slot; + let mut logger = gamelog::Logger::new(); + + // Remove any items target has in item's slot + let mut to_unequip: Vec = 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); + } + } + for item in to_unequip.iter() { + equipped.remove(*item); + backpack.insert(*item, InBackpack { owner: target }).expect("Unable to insert backpack"); + if target == *player_entity { + logger = logger + .append("You remove your") + .append_n(obfuscate_name(*item, &names, &magic_items, &obfuscated_names, &dm, None).0) + .colour(item_colour_u8(*item, &names, &magic_items, &dm)) + .period(); + } + } + + // Wield the item + equipped + .insert(wants_to_use_item.item, Equipped { owner: target, slot: target_slot }) + .expect("Unable to insert equipped component"); + backpack.remove(wants_to_use_item.item); + if target == *player_entity { + logger = logger + .append("You equip the") + .append_n( + obfuscate_name(wants_to_use_item.item, &names, &magic_items, &obfuscated_names, &dm, None) + .0, + ) + .colour(item_colour_u8(wants_to_use_item.item, &names, &magic_items, &dm)) + .period(); + logger.log(); + } + remove.push(target); + } + } + remove.iter().for_each(|e| { + dirty.insert(*e, EquipmentChanged {}).expect("Unabble to insert EquipmentChanged"); + wants_to_use_item.remove(*e).expect("Unable to remove *e"); + }) + } +} diff --git a/src/inventory/mod.rs b/src/inventory/mod.rs index 5fa5336..47d1280 100644 --- a/src/inventory/mod.rs +++ b/src/inventory/mod.rs @@ -8,11 +8,12 @@ use super::{ mod collection_system; mod drop_system; +mod equip_system; mod identification_system; mod remove_system; mod use_system; pub use { - collection_system::ItemCollectionSystem, drop_system::ItemDropSystem, + collection_system::ItemCollectionSystem, drop_system::ItemDropSystem, equip_system::ItemEquipSystem, identification_system::ItemIdentificationSystem, remove_system::ItemRemoveSystem, use_system::ItemUseSystem, }; diff --git a/src/inventory/remove_system.rs b/src/inventory/remove_system.rs index 1b33f50..2d2df45 100644 --- a/src/inventory/remove_system.rs +++ b/src/inventory/remove_system.rs @@ -1,4 +1,5 @@ -use super::{gamelog, Equipped, InBackpack, Name, WantsToRemoveItem}; +use super::{gamelog, Equipped, InBackpack, MagicItem, MasterDungeonMap, Name, ObfuscatedName, WantsToRemoveItem}; +use crate::gui::{item_colour_u8, obfuscate_name}; use specs::prelude::*; pub struct ItemRemoveSystem {} @@ -12,16 +13,34 @@ impl<'a> System<'a> for ItemRemoveSystem { WriteStorage<'a, WantsToRemoveItem>, WriteStorage<'a, Equipped>, WriteStorage<'a, InBackpack>, + ReadStorage<'a, MagicItem>, + ReadStorage<'a, ObfuscatedName>, + ReadExpect<'a, MasterDungeonMap>, ); fn run(&mut self, data: Self::SystemData) { - let (entities, player_entity, names, mut wants_remove, mut equipped, mut backpack) = data; + let ( + entities, + player_entity, + names, + mut wants_remove, + mut equipped, + mut backpack, + magic_items, + obfuscated_names, + dm, + ) = data; for (entity, to_remove) in (&entities, &wants_remove).join() { equipped.remove(to_remove.item); - if let Some(name) = names.get(to_remove.item) { + if let Some(_) = names.get(to_remove.item) { if entity == *player_entity { - gamelog::Logger::new().append("You unequip the").item_name_n(&name.name).period().log(); + gamelog::Logger::new() + .append("You unequip the") + .append_n(obfuscate_name(to_remove.item, &names, &magic_items, &obfuscated_names, &dm, None).0) + .colour(item_colour_u8(to_remove.item, &names, &magic_items, &dm)) + .period() + .log(); } } backpack.insert(to_remove.item, InBackpack { owner: entity }).expect("Unable to insert backpack"); diff --git a/src/inventory/use_system.rs b/src/inventory/use_system.rs index 0b1bc32..286b8c4 100644 --- a/src/inventory/use_system.rs +++ b/src/inventory/use_system.rs @@ -1,16 +1,14 @@ use super::{ - gamelog, Confusion, Consumable, Cursed, Destructible, Digger, EquipmentChanged, Equippable, Equipped, HungerClock, - HungerState, IdentifiedItem, InBackpack, InflictsDamage, MagicMapper, Map, Name, ParticleBuilder, Point, Pools, - Position, ProvidesHealing, ProvidesNutrition, RandomNumberGenerator, RunState, SufferDamage, TileType, Viewshed, - Wand, WantsToUseItem, AOE, DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME, + gamelog, Confusion, Consumable, Cursed, Destructible, Digger, HungerClock, HungerState, IdentifiedItem, + InflictsDamage, MagicMapper, Map, Name, ParticleBuilder, Point, Pools, Position, ProvidesHealing, + ProvidesNutrition, RandomNumberGenerator, RunState, SufferDamage, TileType, Viewshed, Wand, WantsToUseItem, AOE, + DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME, }; use specs::prelude::*; // Grouping together components because of type complexity issues - SystemData was too large. // This is a temporary solution that'll be fixed once inventory use is refactored into separate // systems. -type EquipComponents<'a> = - (ReadStorage<'a, Equippable>, WriteStorage<'a, Equipped>, WriteStorage<'a, EquipmentChanged>); type NameComponents<'a> = (ReadStorage<'a, Name>, WriteStorage<'a, IdentifiedItem>); pub struct ItemUseSystem {} @@ -40,8 +38,6 @@ impl<'a> System<'a> for ItemUseSystem { WriteStorage<'a, Confusion>, ReadStorage<'a, MagicMapper>, WriteExpect<'a, RunState>, - EquipComponents<'a>, - WriteStorage<'a, InBackpack>, WriteStorage<'a, Viewshed>, ); @@ -70,15 +66,10 @@ impl<'a> System<'a> for ItemUseSystem { mut confused, magic_mapper, mut runstate, - (equippable, mut equipped, mut equipment_changed), - mut backpack, mut viewsheds, ) = data; for (entity, wants_to_use) in (&entities, &wants_to_use).join() { - // Could probably limit this insert only to if something is consumed/equipped/etc., but this is - // safer and items aren't used nearly frequently enough for this to cause performance issues. - equipment_changed.insert(entity, EquipmentChanged {}).expect("Unable to insert EquipmentChanged."); let mut verb = "use"; let mut used_item = true; let mut aoe_item = false; @@ -107,10 +98,6 @@ impl<'a> System<'a> for ItemUseSystem { if let Some(_) = is_edible { verb = "eat"; } - let item_equippable = equippable.get(wants_to_use.item); - if let Some(_) = item_equippable { - verb = "equip" - } logger = logger.append(format!("You {} the", verb)).item_name_n(format!("{}", &item_being_used.name)).period(); @@ -187,38 +174,6 @@ impl<'a> System<'a> for ItemUseSystem { } } - // EQUIPMENT - match item_equippable { - None => {} - Some(can_equip) => { - let target_slot = can_equip.slot; - let target = targets[0]; - - // Remove any items target has in item's slot - let mut to_unequip: Vec = 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); - } - } - for item in to_unequip.iter() { - equipped.remove(*item); - backpack.insert(*item, InBackpack { owner: target }).expect("Unable to insert backpack"); - if target == *player_entity { - if let Some(name) = names.get(*item) { - logger = logger.append("You remove your").item_name_n(&name.name).period(); - } - } - } - - // Wield the item - equipped - .insert(wants_to_use.item, Equipped { owner: target, slot: target_slot }) - .expect("Unable to insert equipped component"); - backpack.remove(wants_to_use.item); - } - } - // HEALING ITEM let item_heals = provides_healing.get(wants_to_use.item); match item_heals { diff --git a/src/main.rs b/src/main.rs index 254a53c..bffa226 100644 --- a/src/main.rs +++ b/src/main.rs @@ -99,6 +99,7 @@ impl State { let mut melee_system = MeleeCombatSystem {}; let mut damage_system = DamageSystem {}; let mut inventory_system = inventory::ItemCollectionSystem {}; + let mut item_equip_system = inventory::ItemEquipSystem {}; let mut item_use_system = inventory::ItemUseSystem {}; let mut item_drop_system = inventory::ItemDropSystem {}; let mut item_remove_system = inventory::ItemRemoveSystem {}; @@ -116,6 +117,7 @@ impl State { self.run_ai(); trigger_system.run_now(&self.ecs); inventory_system.run_now(&self.ecs); + item_equip_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);