From 9a0e931897cddfbe59955291616ef14ed6d7d741 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Fri, 21 Jan 2022 11:18:53 -0500 Subject: [PATCH] Implement cursed items --- src/components/tags.rs | 3 + src/gui.rs | 23 +++++-- src/inventory_system/remove_system.rs | 18 +++++- src/inventory_system/use_equip.rs | 87 +++++++++++++++++++-------- src/main.rs | 1 + src/raws/item_structs.rs | 1 + src/raws/rawmaster.rs | 6 ++ src/saveload_system.rs | 2 + 8 files changed, 107 insertions(+), 34 deletions(-) diff --git a/src/components/tags.rs b/src/components/tags.rs index 07b7174..dea48d9 100644 --- a/src/components/tags.rs +++ b/src/components/tags.rs @@ -42,3 +42,6 @@ pub struct EquipmentChanged {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct TownPortal {} + +#[derive(Component, Debug, Serialize, Deserialize, Clone)] +pub struct CursedItem {} diff --git a/src/gui.rs b/src/gui.rs index cf4b92f..e3635ee 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -9,23 +9,34 @@ pub use enums::*; use tooltip::draw_tooltips; use crate::components::{ - Attribute, Attributes, Consumable, Equipped, HungerClock, HungerState, InBackpack, Item, - MagicItem, MagicItemClass, Name, ObfuscatedName, Pools, Vendor, Viewshed, + Attribute, Attributes, Consumable, CursedItem, Equipped, HungerClock, HungerState, InBackpack, + Item, MagicItem, MagicItemClass, Name, ObfuscatedName, Pools, Vendor, Viewshed, }; use crate::game_log::GameLog; use crate::rex_assets::RexAssets; use crate::{camera, colors, Map, MasterDungeonMap, RunState, State, VendorMode}; pub fn get_item_color(ecs: &World, item: Entity) -> RGB { + let dm = ecs.fetch::(); + + // If the item is cursed, and you have identified it, display it in red + if let Some(name) = ecs.read_storage::().get(item) { + if ecs.read_storage::().get(item).is_some() + && dm.identified_items.contains(&name.name) + { + return colors::RED; + } + } + if let Some(magic) = ecs.read_storage::().get(item) { - match magic.class { + return match magic.class { MagicItemClass::Common => colors::EQUIP_COMMON, MagicItemClass::Rare => colors::EQUIP_RARE, MagicItemClass::Legendary => colors::EQUIP_LEGEND, - } - } else { - colors::WHITE + }; } + + colors::WHITE } pub fn get_item_display_name(ecs: &World, item: Entity) -> String { diff --git a/src/inventory_system/remove_system.rs b/src/inventory_system/remove_system.rs index a3ac1f6..2332ac5 100644 --- a/src/inventory_system/remove_system.rs +++ b/src/inventory_system/remove_system.rs @@ -1,6 +1,7 @@ use ::specs::prelude::*; -use crate::components::{Equipped, InBackpack, WantsToRemoveItem}; +use crate::components::{CursedItem, Equipped, InBackpack, Name, WantsToRemoveItem}; +use crate::GameLog; pub struct ItemRemoveSystem {} @@ -11,12 +12,25 @@ impl<'a> System<'a> for ItemRemoveSystem { WriteStorage<'a, WantsToRemoveItem>, WriteStorage<'a, Equipped>, WriteStorage<'a, InBackpack>, + ReadStorage<'a, CursedItem>, + WriteExpect<'a, GameLog>, + ReadStorage<'a, Name>, ); fn run(&mut self, data: Self::SystemData) { - let (entities, mut wants_remove, mut equipped, mut backpack) = data; + let (entities, mut wants_remove, mut equipped, mut backpack, cursed, mut gamelog, names) = + data; for (entity, to_remove) in (&entities, &wants_remove).join() { + if cursed.get(to_remove.item).is_some() { + gamelog.append(format!( + "You cannot remove {}, it is cursed", + names.get(to_remove.item).unwrap().name + )); + + continue; + } + equipped.remove(to_remove.item); backpack .insert(to_remove.item, InBackpack { owner: entity }) diff --git a/src/inventory_system/use_equip.rs b/src/inventory_system/use_equip.rs index a5a10f2..7fe1085 100644 --- a/src/inventory_system/use_equip.rs +++ b/src/inventory_system/use_equip.rs @@ -1,6 +1,10 @@ use ::specs::prelude::*; -use crate::components::{EquipmentChanged, Equippable, Equipped, InBackpack, Name, WantsToUseItem}; +use crate::components::{ + CursedItem, EquipmentChanged, Equippable, Equipped, IdentifiedItem, InBackpack, Name, + WantsToUseItem, +}; + use crate::GameLog; pub struct ItemEquipOnUse {} @@ -17,6 +21,8 @@ impl<'a> System<'a> for ItemEquipOnUse { WriteStorage<'a, Equipped>, WriteStorage<'a, InBackpack>, WriteStorage<'a, EquipmentChanged>, + WriteStorage<'a, IdentifiedItem>, + ReadStorage<'a, CursedItem>, ); fn run(&mut self, data: Self::SystemData) { @@ -30,6 +36,8 @@ impl<'a> System<'a> for ItemEquipOnUse { mut equipped, mut backpack, mut dirty, + mut identified_item, + cursed, ) = data; let mut remove_use = Vec::new(); @@ -40,38 +48,65 @@ impl<'a> System<'a> for ItemEquipOnUse { let target_slot = can_equip.slot; // Remove any items the target has in the item's slot + let mut can_equip = true; + let mut log_entries: Vec = Vec::new(); let mut to_unequip = 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.append(format!("You un-equip {}.", name.name)); + if cursed.get(item_entity).is_some() { + can_equip = false; + gamelog + .append(format!("You cannot un-equip {}, it is cursed.", name.name)) + } else { + to_unequip.push(item_entity); + if target == *player_entity { + log_entries.push(format!("You un-equip {}.", name.name)); + } } } } - for item in to_unequip.iter() { - equipped.remove(*item); - backpack - .insert(*item, InBackpack { owner: target }) - .expect("Unable to move equipped item to backpack."); - } - // Wield the item - equipped - .insert( - useitem.item, - Equipped { - owner: target, - slot: target_slot, - }, - ) - .expect("Unable to equip item"); - backpack.remove(useitem.item); - if target == *player_entity { - gamelog.append(format!( - "You equip {}.", - names.get(useitem.item).unwrap().name - )); + if can_equip { + // Identify the item + if target == *player_entity { + identified_item + .insert( + target, + IdentifiedItem { + name: names.get(useitem.item).unwrap().name.clone(), + }, + ) + .expect("Unable to identify item."); + } + + for item in to_unequip.iter() { + equipped.remove(*item); + backpack + .insert(*item, InBackpack { owner: target }) + .expect("Unable to move equipped item to backpack."); + } + + for entry in log_entries.iter() { + gamelog.append(entry); + } + + // Wield the item + equipped + .insert( + useitem.item, + Equipped { + owner: target, + slot: target_slot, + }, + ) + .expect("Unable to equip item"); + backpack.remove(useitem.item); + if target == *player_entity { + gamelog.append(format!( + "You equip {}.", + names.get(useitem.item).unwrap().name + )); + } } // Done with item diff --git a/src/main.rs b/src/main.rs index 943f69a..accb798 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,6 +64,7 @@ fn init_state() -> State { Chasing, Confusion, Consumable, + CursedItem, Door, DMSerializationHelper, EntityMoved, diff --git a/src/raws/item_structs.rs b/src/raws/item_structs.rs index eb08d10..b3af073 100644 --- a/src/raws/item_structs.rs +++ b/src/raws/item_structs.rs @@ -47,4 +47,5 @@ pub struct Wearable { pub struct MagicItem { pub class: String, pub naming: String, + pub cursed: Option, } diff --git a/src/raws/rawmaster.rs b/src/raws/rawmaster.rs index 809823f..1e91a48 100644 --- a/src/raws/rawmaster.rs +++ b/src/raws/rawmaster.rs @@ -429,6 +429,12 @@ pub fn spawn_named_item( } } } + + if let Some(cursed) = magic.cursed { + if cursed { + eb = eb.with(CursedItem {}); + } + } } return Some(eb.build()); diff --git a/src/saveload_system.rs b/src/saveload_system.rs index 1c5664c..5c0525a 100644 --- a/src/saveload_system.rs +++ b/src/saveload_system.rs @@ -69,6 +69,7 @@ pub fn save_game(ecs: &mut World) { Chasing, Confusion, Consumable, + CursedItem, Door, DMSerializationHelper, EntityMoved, @@ -186,6 +187,7 @@ pub fn load_game(ecs: &mut World) { Chasing, Confusion, Consumable, + CursedItem, Door, DMSerializationHelper, EntityMoved,