Implement cursed items

This commit is contained in:
Timothy Warren 2022-01-21 11:18:53 -05:00
parent 8819fabcca
commit 9a0e931897
8 changed files with 107 additions and 34 deletions

View File

@ -42,3 +42,6 @@ pub struct EquipmentChanged {}
#[derive(Component, Debug, Serialize, Deserialize, Clone)] #[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct TownPortal {} pub struct TownPortal {}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct CursedItem {}

View File

@ -9,24 +9,35 @@ pub use enums::*;
use tooltip::draw_tooltips; use tooltip::draw_tooltips;
use crate::components::{ use crate::components::{
Attribute, Attributes, Consumable, Equipped, HungerClock, HungerState, InBackpack, Item, Attribute, Attributes, Consumable, CursedItem, Equipped, HungerClock, HungerState, InBackpack,
MagicItem, MagicItemClass, Name, ObfuscatedName, Pools, Vendor, Viewshed, Item, MagicItem, MagicItemClass, Name, ObfuscatedName, Pools, Vendor, Viewshed,
}; };
use crate::game_log::GameLog; use crate::game_log::GameLog;
use crate::rex_assets::RexAssets; use crate::rex_assets::RexAssets;
use crate::{camera, colors, Map, MasterDungeonMap, RunState, State, VendorMode}; use crate::{camera, colors, Map, MasterDungeonMap, RunState, State, VendorMode};
pub fn get_item_color(ecs: &World, item: Entity) -> RGB { pub fn get_item_color(ecs: &World, item: Entity) -> RGB {
let dm = ecs.fetch::<crate::map::MasterDungeonMap>();
// If the item is cursed, and you have identified it, display it in red
if let Some(name) = ecs.read_storage::<Name>().get(item) {
if ecs.read_storage::<CursedItem>().get(item).is_some()
&& dm.identified_items.contains(&name.name)
{
return colors::RED;
}
}
if let Some(magic) = ecs.read_storage::<MagicItem>().get(item) { if let Some(magic) = ecs.read_storage::<MagicItem>().get(item) {
match magic.class { return match magic.class {
MagicItemClass::Common => colors::EQUIP_COMMON, MagicItemClass::Common => colors::EQUIP_COMMON,
MagicItemClass::Rare => colors::EQUIP_RARE, MagicItemClass::Rare => colors::EQUIP_RARE,
MagicItemClass::Legendary => colors::EQUIP_LEGEND, MagicItemClass::Legendary => colors::EQUIP_LEGEND,
};
} }
} else {
colors::WHITE colors::WHITE
} }
}
pub fn get_item_display_name(ecs: &World, item: Entity) -> String { pub fn get_item_display_name(ecs: &World, item: Entity) -> String {
if let Some(name) = ecs.read_storage::<Name>().get(item) { if let Some(name) = ecs.read_storage::<Name>().get(item) {

View File

@ -1,6 +1,7 @@
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::{Equipped, InBackpack, WantsToRemoveItem}; use crate::components::{CursedItem, Equipped, InBackpack, Name, WantsToRemoveItem};
use crate::GameLog;
pub struct ItemRemoveSystem {} pub struct ItemRemoveSystem {}
@ -11,12 +12,25 @@ impl<'a> System<'a> for ItemRemoveSystem {
WriteStorage<'a, WantsToRemoveItem>, WriteStorage<'a, WantsToRemoveItem>,
WriteStorage<'a, Equipped>, WriteStorage<'a, Equipped>,
WriteStorage<'a, InBackpack>, WriteStorage<'a, InBackpack>,
ReadStorage<'a, CursedItem>,
WriteExpect<'a, GameLog>,
ReadStorage<'a, Name>,
); );
fn run(&mut self, data: Self::SystemData) { 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() { 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); equipped.remove(to_remove.item);
backpack backpack
.insert(to_remove.item, InBackpack { owner: entity }) .insert(to_remove.item, InBackpack { owner: entity })

View File

@ -1,6 +1,10 @@
use ::specs::prelude::*; 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; use crate::GameLog;
pub struct ItemEquipOnUse {} pub struct ItemEquipOnUse {}
@ -17,6 +21,8 @@ impl<'a> System<'a> for ItemEquipOnUse {
WriteStorage<'a, Equipped>, WriteStorage<'a, Equipped>,
WriteStorage<'a, InBackpack>, WriteStorage<'a, InBackpack>,
WriteStorage<'a, EquipmentChanged>, WriteStorage<'a, EquipmentChanged>,
WriteStorage<'a, IdentifiedItem>,
ReadStorage<'a, CursedItem>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
@ -30,6 +36,8 @@ impl<'a> System<'a> for ItemEquipOnUse {
mut equipped, mut equipped,
mut backpack, mut backpack,
mut dirty, mut dirty,
mut identified_item,
cursed,
) = data; ) = data;
let mut remove_use = Vec::new(); let mut remove_use = Vec::new();
@ -40,15 +48,37 @@ impl<'a> System<'a> for ItemEquipOnUse {
let target_slot = can_equip.slot; let target_slot = can_equip.slot;
// Remove any items the target has in the item's slot // Remove any items the target has in the item's slot
let mut can_equip = true;
let mut log_entries: Vec<String> = Vec::new();
let mut to_unequip = Vec::new(); let mut to_unequip = Vec::new();
for (item_entity, already_equipped, name) in (&entities, &equipped, &names).join() { for (item_entity, already_equipped, name) in (&entities, &equipped, &names).join() {
if already_equipped.owner == target && already_equipped.slot == target_slot { if already_equipped.owner == target && already_equipped.slot == target_slot {
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); to_unequip.push(item_entity);
if target == *player_entity { if target == *player_entity {
gamelog.append(format!("You un-equip {}.", name.name)); log_entries.push(format!("You un-equip {}.", name.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() { for item in to_unequip.iter() {
equipped.remove(*item); equipped.remove(*item);
backpack backpack
@ -56,6 +86,10 @@ impl<'a> System<'a> for ItemEquipOnUse {
.expect("Unable to move equipped item to backpack."); .expect("Unable to move equipped item to backpack.");
} }
for entry in log_entries.iter() {
gamelog.append(entry);
}
// Wield the item // Wield the item
equipped equipped
.insert( .insert(
@ -73,6 +107,7 @@ impl<'a> System<'a> for ItemEquipOnUse {
names.get(useitem.item).unwrap().name names.get(useitem.item).unwrap().name
)); ));
} }
}
// Done with item // Done with item
remove_use.push(target); remove_use.push(target);

View File

@ -64,6 +64,7 @@ fn init_state() -> State {
Chasing, Chasing,
Confusion, Confusion,
Consumable, Consumable,
CursedItem,
Door, Door,
DMSerializationHelper, DMSerializationHelper,
EntityMoved, EntityMoved,

View File

@ -47,4 +47,5 @@ pub struct Wearable {
pub struct MagicItem { pub struct MagicItem {
pub class: String, pub class: String,
pub naming: String, pub naming: String,
pub cursed: Option<bool>,
} }

View File

@ -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()); return Some(eb.build());

View File

@ -69,6 +69,7 @@ pub fn save_game(ecs: &mut World) {
Chasing, Chasing,
Confusion, Confusion,
Consumable, Consumable,
CursedItem,
Door, Door,
DMSerializationHelper, DMSerializationHelper,
EntityMoved, EntityMoved,
@ -186,6 +187,7 @@ pub fn load_game(ecs: &mut World) {
Chasing, Chasing,
Confusion, Confusion,
Consumable, Consumable,
CursedItem,
Door, Door,
DMSerializationHelper, DMSerializationHelper,
EntityMoved, EntityMoved,