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,
}
#[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
// 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.print_color_centered(20, colors::YELLOW, colors::BLACK, "Rust Roguelike Tutorial");
ctx.print_color_centered(21, colors::CYAN, colors::BLACK, "by Herbert Wolverson");
ctx.print_color_centered(20, colors::YELLOW, colors::BLACK, "Rust Roguelike");
ctx.print_color_centered(21, colors::CYAN, colors::BLACK, "by Timothy J. Warren");
ctx.print_color_centered(
22,
colors::GRAY,

View File

@ -3,7 +3,7 @@ use ::specs::prelude::*;
use crate::components::*;
use crate::game_log::GameLog;
use crate::particle_system::ParticleBuilder;
use crate::{colors, spatial, Map, RunState};
use crate::{colors, raws, spatial, Map, MasterDungeonMap, RunState};
pub struct ItemCollectionSystem {}
@ -85,6 +85,7 @@ impl<'a> System<'a> for ItemUseSystem {
WriteExpect<'a, RunState>,
WriteStorage<'a, EquipmentChanged>,
ReadStorage<'a, TownPortal>,
WriteStorage<'a, IdentifiedItem>,
);
#[allow(clippy::cognitive_complexity)]
@ -114,6 +115,7 @@ impl<'a> System<'a> for ItemUseSystem {
mut runstate,
mut dirty,
town_portal,
mut identified_item,
) = data;
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
match equippable.get(useitem.item) {
None => {}
@ -468,3 +482,37 @@ impl<'a> System<'a> for ItemRemoveSystem {
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,
Hidden,
HungerClock,
IdentifiedItem,
InBackpack,
InflictsDamage,
Initiative,

View File

@ -196,6 +196,16 @@ pub fn get_scroll_tags() -> Vec<String> {
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>(
pos: SpawnType,
new_entity: EntityBuilder<'a>,
@ -251,7 +261,12 @@ pub fn spawn_named_item(
) -> Option<Entity> {
if raws.item_index.contains_key(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>>();
// Spawn in the specified location
@ -351,6 +366,7 @@ pub fn spawn_named_item(
};
eb = eb.with(MagicItem { class });
if !identified.contains(&item_template.name) {
#[allow(clippy::single_match)]
match magic.naming.as_str() {
"scroll" => {
@ -361,6 +377,7 @@ pub fn spawn_named_item(
_ => {}
}
}
}
return Some(eb.build());
}

View File

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

View File

@ -7,7 +7,7 @@ use crate::game_log::GameLog;
use crate::gui::{self, show_cheat_mode, CheatMenuResult, MainMenuSelection};
use crate::hunger_system::HungerSystem;
use crate::inventory_system::{
ItemCollectionSystem, ItemDropSystem, ItemRemoveSystem, ItemUseSystem,
ItemCollectionSystem, ItemDropSystem, ItemIdentificationSystem, ItemRemoveSystem, ItemUseSystem,
};
use crate::lighting_system::LightingSystem;
use crate::map::{self, *};
@ -127,6 +127,9 @@ impl State {
let mut items = ItemUseSystem {};
items.run_now(&self.ecs);
let mut item_id = ItemIdentificationSystem {};
item_id.run_now(&self.ecs);
let mut drop_items = ItemDropSystem {};
drop_items.run_now(&self.ecs);
@ -466,7 +469,16 @@ impl GameState for State {
let tag = result.2.unwrap();
let price = result.3.unwrap();
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 {
player_pools.gold -= price;
std::mem::drop(pools);