diff --git a/src/data/ids.rs b/src/data/ids.rs index f6475df..017bc3d 100644 --- a/src/data/ids.rs +++ b/src/data/ids.rs @@ -22,7 +22,12 @@ pub fn get_local_desc(id: i32) -> String { pub fn get_local_col(id: i32) -> RGB { let col = match id { ID_TOWN => TO_TOWN_COLOUR, + ID_OVERMAP => TO_OVERMAP_COLOUR, _ => (255, 255, 255), }; return RGB::from_u8(col.0, col.1, col.2); } + +pub fn rgb_to_u8(col: RGB) -> (u8, u8, u8) { + return ((col.r * 255.0) as u8, (col.g * 255.0) as u8, (col.b * 255.0) as u8); +} diff --git a/src/gamelog/builder.rs b/src/gamelog/builder.rs index 7cd39fe..5c66b86 100644 --- a/src/gamelog/builder.rs +++ b/src/gamelog/builder.rs @@ -55,47 +55,4 @@ impl Logger { pub fn log(self) { return append_entry(self.fragments); } - - /// Appends text in YELLOW to the current message logger. - #[allow(unused)] - pub fn npc_name(mut self, text: T) -> Self { - let mut text_with_space = text.to_string(); - text_with_space.push_str(" "); - self.fragments.push(LogFragment { colour: RGB::named(rltk::YELLOW), text: text_with_space }); - return self; - } - - /// Appends text in YELLOW to the current message logger, with no space. - pub fn npc_name_n(mut self, text: T) -> Self { - self.fragments.push(LogFragment { colour: RGB::named(rltk::YELLOW), text: text.to_string() }); - return self; - } - - /// Appends text in CYAN to the current message logger. - pub fn item_name(mut self, text: T) -> Self { - let mut text_with_space = text.to_string(); - text_with_space.push_str(" "); - self.fragments.push(LogFragment { colour: RGB::named(rltk::CYAN), text: text_with_space }); - return self; - } - - /// Appends text in CYAN to the current message logger, with no space. - pub fn item_name_n(mut self, text: T) -> Self { - self.fragments.push(LogFragment { colour: RGB::named(rltk::CYAN), text: text.to_string() }); - return self; - } - - /// Appends text in RED to the current message logger. - #[allow(dead_code)] - pub fn damage(mut self, damage: i32) -> Self { - self.fragments.push(LogFragment { colour: RGB::named(rltk::RED), text: format!("{} ", damage).to_string() }); - return self; - } - - /// Appends text in RED to the current message logger, with no space. - #[allow(dead_code)] - pub fn damage_n(mut self, damage: i32) -> Self { - self.fragments.push(LogFragment { colour: RGB::named(rltk::RED), text: format!("{}", damage).to_string() }); - return self; - } } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index d4b8945..26bfc73 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -599,6 +599,15 @@ pub fn renderable_colour(renderables: &ReadStorage, entity: Entity) }; } +/// Gets renderable colour as tuple of u8 +pub fn renderable_colour_ecs(ecs: &World, entity: Entity) -> (u8, u8, u8) { + return if let Some(renderable) = ecs.read_storage::().get(entity) { + ((renderable.fg.r * 255.0) as u8, (renderable.fg.g * 255.0) as u8, (renderable.fg.b * 255.0) as u8) + } else { + WHITE + }; +} + pub fn item_colour_ecs(ecs: &World, item: Entity) -> (u8, u8, u8) { if let Some(beatitude) = ecs.read_storage::().get(item) { if beatitude.known { diff --git a/src/inventory/collection_system.rs b/src/inventory/collection_system.rs index 3bb4945..0b8b288 100644 --- a/src/inventory/collection_system.rs +++ b/src/inventory/collection_system.rs @@ -1,6 +1,7 @@ use crate::{ gamelog, gui::obfuscate_name, + gui::item_colour, Beatitude, Charges, EquipmentChanged, @@ -11,6 +12,7 @@ use crate::{ ObfuscatedName, Position, WantsToPickupItem, + Renderable, }; use specs::prelude::*; use crate::data::messages; @@ -59,7 +61,8 @@ impl<'a> System<'a> for ItemCollectionSystem { gamelog::Logger ::new() .append(messages::YOU_PICKUP_ITEM) - .item_name_n( + .colour(item_colour(pickup.item, &beatitudes)) + .append_n( format!( "{}", obfuscate_name( @@ -73,6 +76,7 @@ impl<'a> System<'a> for ItemCollectionSystem { ).0 ) ) + .colour(rltk::WHITE) .period() .log(); } diff --git a/src/inventory/drop_system.rs b/src/inventory/drop_system.rs index dd9659e..2722c60 100644 --- a/src/inventory/drop_system.rs +++ b/src/inventory/drop_system.rs @@ -1,6 +1,7 @@ use crate::{ gamelog, gui::obfuscate_name, + gui::item_colour, Beatitude, Charges, EquipmentChanged, @@ -67,7 +68,8 @@ impl<'a> System<'a> for ItemDropSystem { gamelog::Logger ::new() .append(messages::YOU_DROP_ITEM) - .item_name_n( + .colour(item_colour(to_drop.item, &beatitudes)) + .append_n( format!( "{}", obfuscate_name( @@ -81,6 +83,7 @@ impl<'a> System<'a> for ItemDropSystem { ).0 ) ) + .colour(rltk::WHITE) .period() .log(); } diff --git a/src/main.rs b/src/main.rs index f39629a..a70e341 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use rltk::{ GameState, Point, RandomNumberGenerator, Rltk }; use specs::prelude::*; use specs::saveload::{ SimpleMarker, SimpleMarkerAllocator }; +use crate::data::ids::*; extern crate serde; pub mod camera; @@ -175,7 +176,14 @@ impl State { map::dungeon::freeze_entities(&mut self.ecs); self.generate_world_map(id, dest_tile); let mapname = self.ecs.fetch::().name.clone(); - gamelog::Logger::new().append("You head to").npc_name_n(&mapname).period().log(); + gamelog::Logger + ::new() + .append("You head to") + .colour(rgb_to_u8(get_local_col(id))) + .append_n(&mapname) + .colour(rltk::WHITE) + .period() + .log(); gamelog::record_event(EVENT::CHANGED_FLOOR(mapname)); } @@ -315,7 +323,7 @@ impl GameState for State { let player = self.ecs.fetch::(); let mut pools = self.ecs.write_storage::(); let mut player_pools = pools.get_mut(*player).unwrap(); - gamelog::Logger::new().item_name("TOGGLED GOD MODE!").log(); + gamelog::Logger::new().append("TOGGLED GOD MODE!").log(); player_pools.god = !player_pools.god; new_runstate = RunState::AwaitingInput; } diff --git a/src/player.rs b/src/player.rs index 1828979..0df9be6 100644 --- a/src/player.rs +++ b/src/player.rs @@ -2,7 +2,8 @@ use super::{ effects::{ add_effect, EffectType, Targets }, gamelog, gui::obfuscate_name_ecs, - gui::renderable_colour, + gui::renderable_colour_ecs, + gui::item_colour_ecs, raws::Reaction, Attributes, BlocksTile, @@ -50,7 +51,6 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState { let mut doors = ecs.write_storage::(); let mut blocks_visibility = ecs.write_storage::(); let mut blocks_movement = ecs.write_storage::(); - let mut renderables = ecs.write_storage::(); let names = ecs.read_storage::(); let mut rng = ecs.write_resource::(); @@ -82,13 +82,28 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState { let door = doors.get_mut(potential_target); if let Some(door) = door { if door.open == true { + let renderables = ecs.read_storage::(); if multiple_tile_content { if let Some(name) = names.get(potential_target) { - gamelog::Logger::new().append("The").item_name(&name.name).append("is blocked.").log(); + gamelog::Logger + ::new() + .append("The") + .colour(renderable_colour_ecs(ecs, potential_target)) + .append(&name.name) + .colour(WHITE) + .append("is blocked.") + .log(); } } else if rng.roll_dice(1, 6) + attributes.strength.bonus < 2 { if let Some(name) = names.get(potential_target) { - gamelog::Logger::new().append("The").item_name(&name.name).append("resists!").log(); + gamelog::Logger + ::new() + .append("The") + .colour(renderable_colour_ecs(ecs, potential_target)) + .append(&name.name) + .colour(WHITE) + .append("resists!") + .log(); } } else { door.open = false; @@ -98,10 +113,20 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState { blocks_movement .insert(potential_target, BlocksTile {}) .expect("Unable to insert BlocksTile."); - let render_data = renderables.get_mut(potential_target).unwrap(); if let Some(name) = names.get(potential_target) { - gamelog::Logger::new().append("You close the").item_name_n(&name.name).period().log(); + gamelog::Logger + ::new() + .append("You close the") + .colour(renderable_colour_ecs(ecs, potential_target)) + .append_n(&name.name) + .colour(WHITE) + .period() + .log(); } + //Re-get renderables as mutable + std::mem::drop(renderables); + let mut renderables = ecs.write_storage::(); + let render_data = renderables.get_mut(potential_target).unwrap(); render_data.glyph = rltk::to_cp437('+'); // Nethack open door, maybe just use '/' instead. door_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y)); } @@ -138,7 +163,6 @@ pub fn open(i: i32, j: i32, ecs: &mut World) -> RunState { let mut doors = ecs.write_storage::(); let mut blocks_visibility = ecs.write_storage::(); let mut blocks_movement = ecs.write_storage::(); - let mut renderables = ecs.write_storage::(); let names = ecs.read_storage::(); let mut rng = ecs.write_resource::(); @@ -166,18 +190,35 @@ pub fn open(i: i32, j: i32, ecs: &mut World) -> RunState { let door = doors.get_mut(potential_target); if let Some(door) = door { if door.open == false { + let renderables = ecs.read_storage::(); if rng.roll_dice(1, 6) + attributes.strength.bonus < 2 { if let Some(name) = names.get(potential_target) { - gamelog::Logger::new().append("The").item_name(&name.name).append("resists!").log(); + gamelog::Logger + ::new() + .append("The") + .colour(renderable_colour_ecs(ecs, potential_target)) + .append(&name.name) + .colour(WHITE) + .append("resists!") + .log(); } } else { door.open = true; blocks_visibility.remove(potential_target); blocks_movement.remove(potential_target); - let render_data = renderables.get_mut(potential_target).unwrap(); if let Some(name) = names.get(potential_target) { - gamelog::Logger::new().append("You open the").item_name_n(&name.name).period().log(); + gamelog::Logger + ::new() + .append("You open the") + .colour(renderable_colour_ecs(ecs, potential_target)) + .append_n(&name.name) + .colour(WHITE) + .period() + .log(); } + std::mem::drop(renderables); + let mut renderables = ecs.write_storage::(); + let render_data = renderables.get_mut(potential_target).unwrap(); render_data.glyph = rltk::to_cp437('▓'); // Nethack open door, maybe just use '/' instead. door_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y)); } @@ -212,7 +253,6 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState { let mut viewsheds = ecs.write_storage::(); let attributes = ecs.read_storage::(); let map = ecs.fetch::(); - let entities = ecs.entities(); let mut doors = ecs.write_storage::(); let names = ecs.read_storage::(); @@ -245,10 +285,17 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState { } else { let mut last_non_door_target: Option = None; let mut target_name = "thing"; + let mut colour = WHITE; crate::spatial::for_each_tile_content_with_bool(destination_idx, |potential_target| { if let Some(name) = names.get(potential_target) { target_name = &name.name; } + let items = ecs.read_storage::(); + colour = if let Some(_) = items.get(potential_target) { + item_colour_ecs(ecs, potential_target) + } else { + renderable_colour_ecs(ecs, potential_target) + }; // If it's a door, let door = doors.get_mut(potential_target); @@ -262,7 +309,9 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState { gamelog::Logger ::new() .append("As you kick the") - .item_name_n(target_name) + .colour(colour) + .append_n(obfuscate_name_ecs(ecs, potential_target).0) + .colour(WHITE) .append(", it crashes open!") .log(); something_was_destroyed = Some(potential_target); @@ -274,7 +323,9 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState { gamelog::Logger ::new() .append("You kick the") - .item_name_n(target_name) + .colour(colour) + .append_n(obfuscate_name_ecs(ecs, potential_target).0) + .colour(WHITE) .period() .log(); return false; @@ -290,8 +341,15 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState { } return true; }); - if let Some(_) = last_non_door_target { - gamelog::Logger::new().append("You kick the").item_name_n(target_name).period().log(); + if let Some(e) = last_non_door_target { + gamelog::Logger + ::new() + .append("You kick the") + .colour(colour) + .append_n(obfuscate_name_ecs(ecs, e).0) + .colour(WHITE) + .period() + .log(); let mut particle_builder = ecs.write_resource::(); particle_builder.kick(pos.x + delta_x, pos.y + delta_y); // Do something here if it's anything other than a door. @@ -383,7 +441,19 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState if let Some(door) = door { if door.open == false { if let Some(name) = names.get(potential_target) { - gamelog::Logger::new().append("The").item_name(&name.name).append("is in your way.").log(); + let colour = if let Some(_) = ecs.read_storage::().get(potential_target) { + item_colour_ecs(ecs, potential_target) + } else { + renderable_colour_ecs(ecs, potential_target) + }; + gamelog::Logger + ::new() + .append("The") + .colour(colour) + .append_n(&name.name) + .colour(WHITE) + .append("is in your way.") + .log(); } return Some(RunState::AwaitingInput); } @@ -402,12 +472,13 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState } let hidden = ecs.read_storage::(); // Push every entity name in the pile to a vector of strings - let mut item_names: Vec = Vec::new(); + let mut seen_items: Vec<(String, (u8, u8, u8))> = Vec::new(); let mut some = false; crate::spatial::for_each_tile_content(destination_idx, |entity| { if !hidden.get(entity).is_some() && names.get(entity).is_some() { let item_name = obfuscate_name_ecs(ecs, entity).0; - item_names.push(item_name); + let item_colour = item_colour_ecs(ecs, entity); + seen_items.push((item_name, item_colour)); some = true; } }); @@ -417,11 +488,11 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState // that it shouldn't matter. if some { let mut logger = gamelog::Logger::new().append("You see a"); - for i in 0..item_names.len() { - if i > 0 && i < item_names.len() { + for i in 0..seen_items.len() { + if i > 0 && i < seen_items.len() { logger = logger.append(", a"); } - logger = logger.item_name_n(&item_names[i]); + logger = logger.colour(seen_items[i].1).append_n(&seen_items[i].0).colour(WHITE); } logger.period().log(); } @@ -448,11 +519,10 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState for m in swap_entities.iter() { if let Some(name) = names.get(m.0) { - let renderables = ecs.read_storage::(); gamelog::Logger ::new() .append("You swap places with the") - .colour(renderable_colour(&renderables, m.0)) + .colour(renderable_colour_ecs(ecs, m.0)) .append_n(&name.name) .colour(WHITE) .period() diff --git a/src/visibility_system.rs b/src/visibility_system.rs index d299a7b..4a22238 100644 --- a/src/visibility_system.rs +++ b/src/visibility_system.rs @@ -1,4 +1,17 @@ -use super::{ gamelog, Blind, BlocksVisibility, Hidden, Map, Name, Player, Position, Telepath, Viewshed }; +use super::{ + gamelog, + Blind, + BlocksVisibility, + Hidden, + Map, + Name, + Player, + Position, + Telepath, + Viewshed, + Renderable, + gui::renderable_colour, +}; use rltk::{ FieldOfViewAlg::SymmetricShadowcasting, Point }; use specs::prelude::*; @@ -19,6 +32,7 @@ impl<'a> System<'a> for VisibilitySystem { ReadStorage<'a, Name>, ReadStorage<'a, Blind>, ReadStorage<'a, BlocksVisibility>, + ReadStorage<'a, Renderable>, ); fn run(&mut self, data: Self::SystemData) { @@ -34,6 +48,7 @@ impl<'a> System<'a> for VisibilitySystem { names, blind_entities, blocks_visibility, + renderables, ) = data; map.view_blocked.clear(); @@ -82,7 +97,9 @@ impl<'a> System<'a> for VisibilitySystem { gamelog::Logger ::new() .append("You spot a") - .item_name_n(&name.name) + .colour(renderable_colour(&renderables, e)) + .append_n(&name.name) + .colour(rltk::WHITE) .period() .log(); }