id bugfixes

This commit is contained in:
Llywelwyn 2023-08-13 22:05:03 +01:00
parent b8d7194f28
commit 1ec876a10d
7 changed files with 122 additions and 45 deletions

View file

@ -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",

View file

@ -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,

View file

@ -292,7 +292,7 @@ pub enum ItemMenuResult {
}
pub fn print_options(
inventory: BTreeMap<(String, String, (u8, u8, u8)), i32>,
inventory: BTreeMap<UniqueInventoryItem, i32>,
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<UniqueInventoryItem, i32>) -> 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::<Name>().get(item) {
if ecs.read_storage::<MagicItem>().get(item).is_some() {
let dm = ecs.fetch::<crate::map::MasterDungeonMap>();
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::<ObfuscatedName>().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::<crate::Wand>().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<String, Entity>) {
#[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<UniqueInventoryItem, i32>, BTreeMap<String, Entity>) {
let player_entity = ecs.fetch::<Entity>();
let names = ecs.read_storage::<Name>();
let backpack = ecs.read_storage::<InBackpack>();
@ -439,7 +459,7 @@ pub fn get_player_inventory(ecs: &World) -> (BTreeMap<(String, String, (u8, u8,
let renderables = ecs.read_storage::<Renderable>();
let mut inventory_ids: BTreeMap<String, Entity> = BTreeMap::new();
let mut player_inventory: BTreeMap<(String, String, (u8, u8, u8)), i32> = BTreeMap::new();
let mut player_inventory: BTreeMap<UniqueInventoryItem, i32> = 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);

View file

@ -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());

View file

@ -10,19 +10,29 @@ pub struct MasterDungeonMap {
maps: HashMap<i32, Map>,
pub identified_items: HashSet<String>,
pub scroll_map: HashMap<String, (String, String)>,
pub potion_map: HashMap<String, String>,
}
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<String> = 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>) -> 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<Vec<Map>> {
// Obtain master
let dungeon_master = ecs.read_resource::<MasterDungeonMap>();

View file

@ -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::<crate::map::MasterDungeonMap>();
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::<SimpleMarker<SerializeMe>>();
@ -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<String> {
return result;
}
pub fn get_potion_tags() -> Vec<String> {
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 {

View file

@ -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,
);