From 1ec876a10d38e4d9b816ee146ab07f4064222989 Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Sun, 13 Aug 2023 22:05:03 +0100 Subject: [PATCH] id bugfixes --- raws/items.json | 18 ++++++---- src/gui/cheat_menu.rs | 1 - src/gui/mod.rs | 73 ++++++++++++++++++++++++++++------------- src/inventory_system.rs | 4 +-- src/map/dungeon.rs | 33 +++++++++++++++++-- src/raws/rawmaster.rs | 27 ++++++++++++++- src/spawner.rs | 11 ++----- 7 files changed, 122 insertions(+), 45 deletions(-) diff --git a/raws/items.json b/raws/items.json index 3eb7132..7c49cbd 100644 --- a/raws/items.json +++ b/raws/items.json @@ -6,7 +6,8 @@ "weight": 1, "value": 50, "flags": ["CONSUMABLE", "DESTRUCTIBLE"], - "effects": { "provides_healing": "12" } + "effects": { "provides_healing": "12" }, + "magic": { "class": "common", "naming": "potion" } }, { "id": "potion_health_weak", @@ -15,7 +16,8 @@ "weight": 1, "value": 25, "flags": ["CONSUMABLE", "DESTRUCTIBLE"], - "effects": { "provides_healing": "6" } + "effects": { "provides_healing": "6" }, + "magic": { "class": "common", "naming": "potion" } }, { "id": "scroll_magicmissile", @@ -272,7 +274,8 @@ "weight": 2, "value": 100, "flags": ["WAND"], - "effects": { "ranged": "12", "damage": "10" } + "effects": { "ranged": "12", "damage": "10" }, + "magic": { "class": "uncommon", "naming": "wand" } }, { "id": "wand_fireball", @@ -281,7 +284,8 @@ "weight": 2, "value": 300, "flags": ["WAND"], - "effects": { "ranged": "10", "damage": "15", "aoe": "3" } + "effects": { "ranged": "10", "damage": "15", "aoe": "3" }, + "magic": { "class": "rare", "naming": "wand" } }, { "id": "wand_confusion", @@ -290,7 +294,8 @@ "weight": 2, "value": 200, "flags": ["WAND"], - "effects": { "ranged": "10", "confusion": "4" } + "effects": { "ranged": "10", "confusion": "4" }, + "magic": { "class": "uncommon", "naming": "wand" } }, { "id": "wand_digging", @@ -299,7 +304,8 @@ "weight": 2, "value": 300, "flags": ["WAND"], - "effects": { "ranged": "10", "digger": "" } + "effects": { "ranged": "10", "digger": "" }, + "magic": { "class": "rare", "naming": "wand" } }, { "id": "food_rations", diff --git a/src/gui/cheat_menu.rs b/src/gui/cheat_menu.rs index 7068206..76ece1b 100644 --- a/src/gui/cheat_menu.rs +++ b/src/gui/cheat_menu.rs @@ -47,7 +47,6 @@ pub fn show_cheat_menu(_gs: &mut State, ctx: &mut Rltk) -> CheatMenuResult { // Godmode ctx.set(x_offset + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), rltk::to_cp437('g')); ctx.print(x_offset + 4, y, "GOD MODE"); - y += 1; // Match keys match ctx.key { None => CheatMenuResult::NoResponse, diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 3247912..ca05dfd 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -292,7 +292,7 @@ pub enum ItemMenuResult { } pub fn print_options( - inventory: BTreeMap<(String, String, (u8, u8, u8)), i32>, + inventory: BTreeMap, mut x: i32, mut y: i32, ctx: &mut Rltk, @@ -300,8 +300,8 @@ pub fn print_options( let mut j = 0; let initial_x: i32 = x; let mut width: i32 = -1; - for (name, item_count) in &inventory { - let fg = RGB::from_u8(name.2 .0, name.2 .1, name.2 .2); + for (item, item_count) in &inventory { + let fg = RGB::from_u8(item.rgb.0, item.rgb.1, item.rgb.2); x = initial_x; // Print the character required to access this item. i.e. (a) if j < 26 { @@ -318,12 +318,12 @@ pub fn print_options( // i.e. (a) 3 daggers ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), item_count); x += 2; - ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), name.1.to_string()); + ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), item.display_name.singular.to_string()); } else { - if name.0.ends_with("s") { + if item.display_name.singular.ends_with("s") { ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), "some"); x += 5; - } else if ['a', 'e', 'i', 'o', 'u'].iter().any(|&v| name.0.starts_with(v)) { + } else if ['a', 'e', 'i', 'o', 'u'].iter().any(|&v| item.display_name.singular.starts_with(v)) { // If one and starts with a vowel, print 'an' // i.e. (a) an apple ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), "an"); @@ -334,9 +334,9 @@ pub fn print_options( ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), "a"); x += 2; } - ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), name.0.to_string()); + ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), item.display_name.singular.to_string()); } - let this_width = x - initial_x + name.0.len() as i32; + let this_width = x - initial_x + item.display_name.singular.len() as i32; width = if width > this_width { width } else { this_width }; y += 1; @@ -346,15 +346,15 @@ pub fn print_options( return (y, width); } -pub fn get_max_inventory_width(inventory: &BTreeMap<(String, String, (u8, u8, u8)), i32>) -> i32 { +pub fn get_max_inventory_width(inventory: &BTreeMap) -> i32 { let mut width: i32 = 0; - for (name, count) in inventory { - let mut this_width = name.0.len() as i32; + for (item, count) in inventory { + let mut this_width = item.display_name.singular.len() as i32; if count < &1 { this_width += 4; - if name.0.ends_with("s") { + if item.display_name.singular.ends_with("s") { this_width += 3; - } else if ['a', 'e', 'i', 'o', 'u'].iter().any(|&v| name.0.starts_with(v)) { + } else if ['a', 'e', 'i', 'o', 'u'].iter().any(|&v| item.display_name.singular.starts_with(v)) { this_width += 1; } } else { @@ -366,22 +366,29 @@ pub fn get_max_inventory_width(inventory: &BTreeMap<(String, String, (u8, u8, u8 } pub fn get_item_display_name(ecs: &World, item: Entity) -> (String, String) { + let (mut singular, mut plural) = ("nameless item (bug)".to_string(), "nameless items (bug)".to_string()); if let Some(name) = ecs.read_storage::().get(item) { if ecs.read_storage::().get(item).is_some() { let dm = ecs.fetch::(); if dm.identified_items.contains(&name.name) { - return (name.name.clone(), name.plural.clone()); + (singular, plural) = (name.name.clone(), name.plural.clone()); } else if let Some(obfuscated) = ecs.read_storage::().get(item) { - return (obfuscated.name.clone(), obfuscated.plural.clone()); + (singular, plural) = (obfuscated.name.clone(), obfuscated.plural.clone()); } else { - return ("unid magic item".to_string(), "unid magic items".to_string()); + (singular, plural) = ("unid magic item".to_string(), "unid magic items".to_string()); } } else { - return (name.name.clone(), name.plural.clone()); + (singular, plural) = (name.name.clone(), name.plural.clone()); } - } else { - return ("nameless item (bug)".to_string(), "nameless items (bug)".to_string()); } + if let Some(wand) = ecs.read_storage::().get(item) { + let used = wand.max_uses - wand.uses; + for _i in 0..used { + singular.push_str("*"); + plural.push_str("*"); + } + } + return (singular, plural); } pub fn show_help(ctx: &mut Rltk) -> YesNoResult { @@ -431,7 +438,20 @@ pub fn show_help(ctx: &mut Rltk) -> YesNoResult { } } -pub fn get_player_inventory(ecs: &World) -> (BTreeMap<(String, String, (u8, u8, u8)), i32>, BTreeMap) { +#[derive(PartialEq, Eq, PartialOrd, Ord)] +struct DisplayName { + singular: String, + plural: String, +} + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +pub struct UniqueInventoryItem { + display_name: DisplayName, + rgb: (u8, u8, u8), + name: String, +} + +pub fn get_player_inventory(ecs: &World) -> (BTreeMap, BTreeMap) { let player_entity = ecs.fetch::(); let names = ecs.read_storage::(); let backpack = ecs.read_storage::(); @@ -439,7 +459,7 @@ pub fn get_player_inventory(ecs: &World) -> (BTreeMap<(String, String, (u8, u8, let renderables = ecs.read_storage::(); let mut inventory_ids: BTreeMap = BTreeMap::new(); - let mut player_inventory: BTreeMap<(String, String, (u8, u8, u8)), i32> = BTreeMap::new(); + let mut player_inventory: BTreeMap = BTreeMap::new(); for (entity, _pack, name) in (&entities, &backpack, &names).join().filter(|item| item.1.owner == *player_entity) { // RGB can't be used as a key. This is converting the RGB (tuple of f32) into a tuple of u8s. let (r, g, b): (u8, u8, u8) = if let Some(renderable) = renderables.get(entity) { @@ -448,8 +468,15 @@ pub fn get_player_inventory(ecs: &World) -> (BTreeMap<(String, String, (u8, u8, (255, 255, 255) }; let (singular, plural) = get_item_display_name(ecs, entity); - player_inventory.entry((singular, plural, (r, g, b))).and_modify(|count| *count += 1).or_insert(1); - inventory_ids.entry(name.name.to_string()).or_insert(entity); + player_inventory + .entry(UniqueInventoryItem { + display_name: DisplayName { singular: singular.clone(), plural: plural }, + rgb: (r, g, b), + name: name.name.clone(), + }) + .and_modify(|count| *count += 1) + .or_insert(1); + inventory_ids.entry(singular).or_insert(entity); } return (player_inventory, inventory_ids); diff --git a/src/inventory_system.rs b/src/inventory_system.rs index 88e378d..2123e30 100644 --- a/src/inventory_system.rs +++ b/src/inventory_system.rs @@ -136,9 +136,6 @@ impl<'a> System<'a> for ItemUseSystem { consumables.insert(wants_to_use.item, Consumable {}).expect("Could not insert consumable"); } verb = "zap"; - // TODO: Change this to track uses better, after adding in identification. - name.name.push_str("*"); - name.plural.push_str("*"); wand.uses -= 1; } @@ -435,6 +432,7 @@ impl<'a> System<'a> for ItemIdentificationSystem { 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() { + rltk::console::log(id.name.clone()); let tag = crate::raws::get_id_from_name(id.name.clone()); if !dm.identified_items.contains(&id.name) && crate::raws::is_tag_magic(&tag) { dm.identified_items.insert(id.name.clone()); diff --git a/src/map/dungeon.rs b/src/map/dungeon.rs index c9292fb..3e84c00 100644 --- a/src/map/dungeon.rs +++ b/src/map/dungeon.rs @@ -10,19 +10,29 @@ pub struct MasterDungeonMap { maps: HashMap, pub identified_items: HashSet, pub scroll_map: HashMap, + pub potion_map: HashMap, } impl MasterDungeonMap { /// Initialises a blank MasterDungeonMap pub fn new() -> MasterDungeonMap { - let mut dm = - MasterDungeonMap { maps: HashMap::new(), identified_items: HashSet::new(), scroll_map: HashMap::new() }; + let mut dm = MasterDungeonMap { + maps: HashMap::new(), + identified_items: HashSet::new(), + scroll_map: HashMap::new(), + potion_map: HashMap::new(), + }; // TODO: Use stored RNG let mut rng = RandomNumberGenerator::new(); for scroll_tag in crate::raws::get_scroll_tags().iter() { let (unid_singular, unid_plural) = make_scroll_name(&mut rng); dm.scroll_map.insert(scroll_tag.to_string(), (unid_singular, unid_plural)); } + let mut used_potion_names: HashSet = HashSet::new(); + for potion_tag in crate::raws::get_potion_tags().iter() { + let unid_singular = make_potion_name(&mut rng, &mut used_potion_names); + dm.potion_map.insert(potion_tag.to_string(), unid_singular); + } return dm; } @@ -88,6 +98,25 @@ fn make_scroll_name(rng: &mut RandomNumberGenerator) -> (String, String) { return (singular, plural); } +const POTION_COLOURS: &[&str] = + &["red", "orange", "yellow", "green", "blue", "indigo", "violet", "black", "white", "silver", "gold"]; +const POTION_ADJECTIVES: &[&str] = &["swirling", "viscous", "effervescent", "slimy", "oily", "metallic"]; + +fn make_potion_name(rng: &mut RandomNumberGenerator, used_names: &mut HashSet) -> String { + loop { + let mut name: String = + POTION_ADJECTIVES[rng.roll_dice(1, POTION_ADJECTIVES.len() as i32) as usize - 1].to_string(); + name += " "; + name += POTION_COLOURS[rng.roll_dice(1, POTION_COLOURS.len() as i32) as usize - 1]; + name += " potion"; + + if !used_names.contains(&name) { + used_names.insert(name.clone()); + return name; + } + } +} + pub fn level_transition(ecs: &mut World, new_id: i32, offset: i32) -> Option> { // Obtain master let dungeon_master = ecs.read_resource::(); diff --git a/src/raws/rawmaster.rs b/src/raws/rawmaster.rs index 8ec3f33..379e9eb 100644 --- a/src/raws/rawmaster.rs +++ b/src/raws/rawmaster.rs @@ -113,6 +113,7 @@ pub fn spawn_named_item(raws: &RawMaster, ecs: &mut World, key: &str, pos: Spawn let item_template = &raws.raws.items[raws.item_index[key]]; let dm = ecs.fetch::(); let scroll_names = dm.scroll_map.clone(); + let potion_names = dm.potion_map.clone(); let identified_items = dm.identified_items.clone(); std::mem::drop(dm); let mut eb = ecs.create_entity().marked::>(); @@ -190,7 +191,18 @@ pub fn spawn_named_item(raws: &RawMaster, ecs: &mut World, key: &str, pos: Spawn plural: scroll_names[&item_template.name.name].1.clone(), }) } - _ => {} + "potion" => { + let singular = potion_names[&item_template.name.name].clone(); + let mut plural = singular.clone(); + plural += "s"; + eb = eb.with(ObfuscatedName { name: singular, plural: plural }) + } + _ => { + let singular = magic_item.naming.clone(); + let mut plural = singular.clone(); + plural += "s"; + eb = eb.with(ObfuscatedName { name: singular, plural: plural }) + } } } } @@ -661,6 +673,19 @@ pub fn get_scroll_tags() -> Vec { return result; } +pub fn get_potion_tags() -> Vec { + let raws = &super::RAWS.lock().unwrap(); + let mut result = Vec::new(); + for item in raws.raws.items.iter() { + if let Some(magic) = &item.magic { + if &magic.naming == "potion" { + result.push(item.name.name.clone()); + } + } + } + return result; +} + pub fn get_id_from_name(name: String) -> String { let raws = &super::RAWS.lock().unwrap(); for item in &raws.raws.items { diff --git a/src/spawner.rs b/src/spawner.rs index e71ead0..ef311d2 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -72,21 +72,14 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity { raws::spawn_named_entity( &raws::RAWS.lock().unwrap(), ecs, - "scroll_fireball", + "wand_fireball", raws::SpawnType::Carried { by: player }, 0, ); raws::spawn_named_entity( &raws::RAWS.lock().unwrap(), ecs, - "scroll_fireball", - raws::SpawnType::Carried { by: player }, - 0, - ); - raws::spawn_named_entity( - &raws::RAWS.lock().unwrap(), - ecs, - "scroll_fireball", + "wand_magicmissile", raws::SpawnType::Carried { by: player }, 0, );