Allow identifying items by use or purchase

This commit is contained in:
Timothy Warren 2022-01-19 11:04:10 -05:00
parent dd8a3b4f6f
commit 2dc2a4549a
7 changed files with 98 additions and 13 deletions

View File

@ -384,6 +384,11 @@ pub struct ObfuscatedName {
pub name: String, pub name: String,
} }
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct IdentifiedItem {
pub name: String,
}
// Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an // Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an
// Entity. // Entity.

View File

@ -761,8 +761,8 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
ctx.draw_box_double(24, 18, 31, 10, colors::WHEAT, colors::BLACK); ctx.draw_box_double(24, 18, 31, 10, colors::WHEAT, colors::BLACK);
ctx.print_color_centered(20, colors::YELLOW, colors::BLACK, "Rust Roguelike Tutorial"); ctx.print_color_centered(20, colors::YELLOW, colors::BLACK, "Rust Roguelike");
ctx.print_color_centered(21, colors::CYAN, colors::BLACK, "by Herbert Wolverson"); ctx.print_color_centered(21, colors::CYAN, colors::BLACK, "by Timothy J. Warren");
ctx.print_color_centered( ctx.print_color_centered(
22, 22,
colors::GRAY, colors::GRAY,

View File

@ -3,7 +3,7 @@ use ::specs::prelude::*;
use crate::components::*; use crate::components::*;
use crate::game_log::GameLog; use crate::game_log::GameLog;
use crate::particle_system::ParticleBuilder; use crate::particle_system::ParticleBuilder;
use crate::{colors, spatial, Map, RunState}; use crate::{colors, raws, spatial, Map, MasterDungeonMap, RunState};
pub struct ItemCollectionSystem {} pub struct ItemCollectionSystem {}
@ -85,6 +85,7 @@ impl<'a> System<'a> for ItemUseSystem {
WriteExpect<'a, RunState>, WriteExpect<'a, RunState>,
WriteStorage<'a, EquipmentChanged>, WriteStorage<'a, EquipmentChanged>,
ReadStorage<'a, TownPortal>, ReadStorage<'a, TownPortal>,
WriteStorage<'a, IdentifiedItem>,
); );
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
@ -114,6 +115,7 @@ impl<'a> System<'a> for ItemUseSystem {
mut runstate, mut runstate,
mut dirty, mut dirty,
town_portal, town_portal,
mut identified_item,
) = data; ) = data;
for (entity, useitem) in (&entities, &wants_use).join() { for (entity, useitem) in (&entities, &wants_use).join() {
@ -161,6 +163,18 @@ impl<'a> System<'a> for ItemUseSystem {
} }
} }
// Identify
if entity == *player_entity {
identified_item
.insert(
entity,
IdentifiedItem {
name: names.get(useitem.item).unwrap().name.clone(),
},
)
.expect("Unable to identify item");
}
// If it is equippable, then we want to equip it - and unequip whatever else was in that slot // If it is equippable, then we want to equip it - and unequip whatever else was in that slot
match equippable.get(useitem.item) { match equippable.get(useitem.item) {
None => {} None => {}
@ -468,3 +482,37 @@ impl<'a> System<'a> for ItemRemoveSystem {
wants_remove.clear(); wants_remove.clear();
} }
} }
pub struct ItemIdentificationSystem {}
impl<'a> System<'a> for ItemIdentificationSystem {
#[allow(clippy::type_complexity)]
type SystemData = (
ReadStorage<'a, Player>,
WriteStorage<'a, IdentifiedItem>,
WriteExpect<'a, MasterDungeonMap>,
ReadStorage<'a, Item>,
ReadStorage<'a, Name>,
WriteStorage<'a, ObfuscatedName>,
Entities<'a>,
);
fn run(&mut self, data: Self::SystemData) {
let (player, mut identified, mut dm, items, names, mut obfuscated_names, entities) = data;
for (_p, id) in (&player, &identified).join() {
if !dm.identified_items.contains(&id.name) && raws::is_tag_magic(&id.name) {
dm.identified_items.insert(id.name.clone());
for (entity, _item, name) in (&entities, &items, &names).join() {
if name.name == id.name {
obfuscated_names.remove(entity);
}
}
}
}
// Clean up
identified.clear();
}
}

View File

@ -78,6 +78,7 @@ fn main() -> ::rltk::BError {
Faction, Faction,
Hidden, Hidden,
HungerClock, HungerClock,
IdentifiedItem,
InBackpack, InBackpack,
InflictsDamage, InflictsDamage,
Initiative, Initiative,

View File

@ -196,6 +196,16 @@ pub fn get_scroll_tags() -> Vec<String> {
result result
} }
pub fn is_tag_magic(tag: &str) -> bool {
let raws = &RAWS.lock().unwrap();
if raws.item_index.contains_key(tag) {
let item_template = &raws.raws.items[raws.item_index[tag]];
item_template.magic.is_some()
} else {
false
}
}
fn spawn_position<'a>( fn spawn_position<'a>(
pos: SpawnType, pos: SpawnType,
new_entity: EntityBuilder<'a>, new_entity: EntityBuilder<'a>,
@ -251,7 +261,12 @@ pub fn spawn_named_item(
) -> Option<Entity> { ) -> Option<Entity> {
if raws.item_index.contains_key(key) { if raws.item_index.contains_key(key) {
let item_template = &raws.raws.items[raws.item_index[key]]; let item_template = &raws.raws.items[raws.item_index[key]];
let scroll_names = ecs.fetch::<MasterDungeonMap>().scroll_mappings.clone();
let dm = ecs.fetch::<MasterDungeonMap>();
let scroll_names = dm.scroll_mappings.clone();
let identified = dm.identified_items.clone();
std::mem::drop(dm);
let mut eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>(); let mut eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
// Spawn in the specified location // Spawn in the specified location
@ -351,6 +366,7 @@ pub fn spawn_named_item(
}; };
eb = eb.with(MagicItem { class }); eb = eb.with(MagicItem { class });
if !identified.contains(&item_template.name) {
#[allow(clippy::single_match)] #[allow(clippy::single_match)]
match magic.naming.as_str() { match magic.naming.as_str() {
"scroll" => { "scroll" => {
@ -361,6 +377,7 @@ pub fn spawn_named_item(
_ => {} _ => {}
} }
} }
}
return Some(eb.build()); return Some(eb.build());
} }

View File

@ -80,6 +80,7 @@ pub fn save_game(ecs: &mut World) {
Faction, Faction,
Hidden, Hidden,
HungerClock, HungerClock,
IdentifiedItem,
InBackpack, InBackpack,
InflictsDamage, InflictsDamage,
Initiative, Initiative,
@ -195,6 +196,7 @@ pub fn load_game(ecs: &mut World) {
Faction, Faction,
Hidden, Hidden,
HungerClock, HungerClock,
IdentifiedItem,
InBackpack, InBackpack,
InflictsDamage, InflictsDamage,
Initiative, Initiative,

View File

@ -7,7 +7,7 @@ use crate::game_log::GameLog;
use crate::gui::{self, show_cheat_mode, CheatMenuResult, MainMenuSelection}; use crate::gui::{self, show_cheat_mode, CheatMenuResult, MainMenuSelection};
use crate::hunger_system::HungerSystem; use crate::hunger_system::HungerSystem;
use crate::inventory_system::{ use crate::inventory_system::{
ItemCollectionSystem, ItemDropSystem, ItemRemoveSystem, ItemUseSystem, ItemCollectionSystem, ItemDropSystem, ItemIdentificationSystem, ItemRemoveSystem, ItemUseSystem,
}; };
use crate::lighting_system::LightingSystem; use crate::lighting_system::LightingSystem;
use crate::map::{self, *}; use crate::map::{self, *};
@ -127,6 +127,9 @@ impl State {
let mut items = ItemUseSystem {}; let mut items = ItemUseSystem {};
items.run_now(&self.ecs); items.run_now(&self.ecs);
let mut item_id = ItemIdentificationSystem {};
item_id.run_now(&self.ecs);
let mut drop_items = ItemDropSystem {}; let mut drop_items = ItemDropSystem {};
drop_items.run_now(&self.ecs); drop_items.run_now(&self.ecs);
@ -466,7 +469,16 @@ impl GameState for State {
let tag = result.2.unwrap(); let tag = result.2.unwrap();
let price = result.3.unwrap(); let price = result.3.unwrap();
let mut pools = self.ecs.write_storage::<Pools>(); let mut pools = self.ecs.write_storage::<Pools>();
let player_pools = pools.get_mut(*self.ecs.fetch::<Entity>()).unwrap(); let player_entity = self.ecs.fetch::<Entity>();
let mut identified = self.ecs.write_storage::<IdentifiedItem>();
identified
.insert(*player_entity, IdentifiedItem { name: tag.clone() })
.expect("Unable to identify item");
std::mem::drop(identified);
let player_pools = pools.get_mut(*player_entity).unwrap();
std::mem::drop(player_entity);
if player_pools.gold >= price { if player_pools.gold >= price {
player_pools.gold -= price; player_pools.gold -= price;
std::mem::drop(pools); std::mem::drop(pools);