diff --git a/src/ai/encumbrance_system.rs b/src/ai/encumbrance_system.rs index 4199a66..3aaae9b 100644 --- a/src/ai/encumbrance_system.rs +++ b/src/ai/encumbrance_system.rs @@ -6,8 +6,8 @@ use crate::components::{ AttributeBonus, Attributes, EquipmentChanged, Equipped, InBackpack, Item, Pools, Slow, StatusEffect, }; -use crate::game_log::GameLog; use crate::gamesystem::attr_bonus; +use crate::{colors, gamelog}; pub struct EncumbranceSystem {} @@ -22,7 +22,6 @@ impl<'a> System<'a> for EncumbranceSystem { WriteStorage<'a, Pools>, WriteStorage<'a, Attributes>, ReadExpect<'a, Entity>, - WriteExpect<'a, GameLog>, ReadStorage<'a, AttributeBonus>, ReadStorage<'a, StatusEffect>, ReadStorage<'a, Slow>, @@ -38,7 +37,6 @@ impl<'a> System<'a> for EncumbranceSystem { mut pools, mut attributes, player, - mut gamelog, attrbonus, statuses, slowed, @@ -133,7 +131,8 @@ impl<'a> System<'a> for EncumbranceSystem { // Overburdened pool.total_initiative_penalty += 4.0; if *entity == *player { - gamelog.append( + gamelog::log_color_line( + colors::ORANGE, "You are overburdened, and suffering an initiative penalty.", ); } diff --git a/src/ai/quipping.rs b/src/ai/quipping.rs index 1964f24..4576d4f 100644 --- a/src/ai/quipping.rs +++ b/src/ai/quipping.rs @@ -2,14 +2,13 @@ use ::rltk::{Point, RandomNumberGenerator}; use ::specs::prelude::*; use crate::components::{MyTurn, Name, Quips, Viewshed}; -use crate::game_log::GameLog; +use crate::{colors, gamelog}; pub struct QuipSystem {} impl<'a> System<'a> for QuipSystem { #[allow(clippy::type_complexity)] type SystemData = ( - WriteExpect<'a, GameLog>, WriteStorage<'a, Quips>, ReadStorage<'a, Name>, ReadStorage<'a, MyTurn>, @@ -19,7 +18,7 @@ impl<'a> System<'a> for QuipSystem { ); fn run(&mut self, data: Self::SystemData) { - let (mut gamelog, mut quips, names, turns, player_pos, viewsheds, mut rng) = data; + let (mut quips, names, turns, player_pos, viewsheds, mut rng) = data; for (quip, name, viewshed, _turn) in (&mut quips, &names, &viewsheds, &turns).join() { if !quip.available.is_empty() @@ -32,10 +31,10 @@ impl<'a> System<'a> for QuipSystem { (rng.roll_dice(1, quip.available.len() as i32) - 1) as usize }; - gamelog.append(format!( - "{} says \"{}\"", - name.name, quip.available[quip_index] - )); + gamelog::color_line(colors::YELLOW, &name.name) + .append_white("says") + .append_color(colors::CYAN, &quip.available[quip_index]) + .log(); quip.available.remove(quip_index); } diff --git a/src/damage_system.rs b/src/damage_system.rs index a009553..5e0103f 100644 --- a/src/damage_system.rs +++ b/src/damage_system.rs @@ -5,9 +5,8 @@ use crate::components::{ AreaOfEffect, Equipped, InBackpack, LootTable, Name, OnDeath, Player, Pools, Position, }; use crate::effects::*; -use crate::game_log::GameLog; use crate::raws::{self, SpawnType, RAWS}; -use crate::{Map, RunState}; +use crate::{colors, gamelog, Map, RunState}; pub fn delete_the_dead(ecs: &mut World) { let mut dead: Vec = Vec::new(); @@ -18,14 +17,15 @@ pub fn delete_the_dead(ecs: &mut World) { let players = ecs.read_storage::(); let names = ecs.read_storage::(); let entities = ecs.entities(); - let mut log = ecs.write_resource::(); for (entity, stats) in (&entities, &combat_stats).join() { if stats.hit_points.current < 1 { match players.get(entity) { None => { if let Some(victim_name) = names.get(entity) { - log.append(format!("{} is dead", &victim_name.name)); + gamelog::color_line(colors::RED, &victim_name.name) + .append("is dead!") + .log(); } dead.push(entity) diff --git a/src/effects/damage.rs b/src/effects/damage.rs index cdca4a3..1b8258d 100644 --- a/src/effects/damage.rs +++ b/src/effects/damage.rs @@ -7,7 +7,7 @@ use crate::components::{ Attributes, Confusion, DamageOverTime, Duration, Name, Player, Pools, SerializeMe, Skills, Slow, }; use crate::gamesystem::{mana_at_level, player_hp_at_level}; -use crate::{colors, EquipmentChanged, GameLog, Map, StatusEffect}; +use crate::{colors, gamelog, EquipmentChanged, Map, StatusEffect}; pub fn inflict_damage(ecs: &mut World, damage: &EffectSpawner, target: Entity) { let mut pools = ecs.write_storage::(); @@ -69,7 +69,6 @@ pub fn death(ecs: &mut World, effect: &EffectSpawner, target: Entity) { } if xp_gain != 0 || gold_gain != 0.0 { - let mut log = ecs.fetch_mut::(); let mut player_stats = pools.get_mut(source).unwrap(); let mut player_attributes = attributes.get_mut(source).unwrap(); player_stats.xp += xp_gain; @@ -77,29 +76,28 @@ pub fn death(ecs: &mut World, effect: &EffectSpawner, target: Entity) { if player_stats.xp >= player_stats.level * 1000 { // We've gone up a level! player_stats.level += 1; - log.append(format!( - "Congratulations, you are now level {}", - player_stats.level - )); + gamelog::color_line(colors::MAGENTA, "Congratulations, you are now level") + .append(format!("{}", player_stats.level)) + .log(); // Improve a random attribute let mut rng = ecs.fetch_mut::(); match rng.roll_dice(1, 4) { 1 => { player_attributes.might.base += 1; - log.append("You feel stronger!"); + gamelog::log_color_line(colors::GREEN, "You feel stronger!"); } 2 => { player_attributes.fitness.base += 1; - log.append("You feel healthier!"); + gamelog::log_color_line(colors::GREEN, "You feel healthier!"); } 3 => { player_attributes.quickness.base += 1; - log.append("You feel quicker!"); + gamelog::log_color_line(colors::GREEN, "You feel quicker!"); } _ => { player_attributes.intelligence.base += 1; - log.append("You feel smarter!"); + gamelog::log_color_line(colors::GREEN, "You feel smarter!"); } } diff --git a/src/effects/triggers.rs b/src/effects/triggers.rs index 520d73b..612ed67 100644 --- a/src/effects/triggers.rs +++ b/src/effects/triggers.rs @@ -11,18 +11,19 @@ use crate::components::{ }; use crate::effects::{aoe_tiles, entity_position, targeting}; use crate::raws::find_spell_entity; -use crate::{colors, GameLog, Map, RunState}; +use crate::{colors, gamelog, Map, RunState}; pub fn item_trigger(creator: Option, item: Entity, targets: &Targets, ecs: &mut World) { // Check charges if let Some(c) = ecs.write_storage::().get_mut(item) { if c.charges < 1 { // Cancel - let mut gamelog = ecs.fetch_mut::(); - gamelog.append(format!( - "{} is out of charges!", - ecs.read_storage::().get(item).unwrap().name - )); + gamelog::color_line( + colors::CYAN, + &ecs.read_storage::().get(item).unwrap().name, + ) + .append_white("is out of charges!") + .log(); return; } else { @@ -114,7 +115,6 @@ fn event_trigger( ecs: &mut World, ) -> bool { let mut did_something = false; - let mut gamelog = ecs.fetch_mut::(); // Simple particle spawn if let Some(part) = ecs.read_storage::().get(entity) { @@ -158,7 +158,9 @@ fn event_trigger( if ecs.read_storage::().get(entity).is_some() { add_effect(creator, EffectType::WellFed, targets.clone()); let names = ecs.read_storage::(); - gamelog.append(format!("You eat the {}.", names.get(entity).unwrap().name)); + gamelog::line("You eat the") + .append_color(colors::CYAN, &names.get(entity).unwrap().name) + .log(); did_something = true; } @@ -166,7 +168,7 @@ fn event_trigger( // Magic mapper if ecs.read_storage::().get(entity).is_some() { let mut runstate = ecs.fetch_mut::(); - gamelog.append("The map is revealed to you!"); + gamelog::log_line("The map is revealed to you!"); *runstate = RunState::MagicMapReveal { row: 0 }; did_something = true; @@ -200,9 +202,9 @@ fn event_trigger( if ecs.read_storage::().get(entity).is_some() { let map = ecs.fetch::(); if map.depth == 1 { - gamelog.append("You are already in town, so the scroll does nothing."); + gamelog::log_line("You are already in town, so the scroll does nothing."); } else { - gamelog.append("You are teleported back to town!"); + gamelog::log_line("You are teleported back to town!"); let mut runstate = ecs.fetch_mut::(); *runstate = RunState::TownPortal; diff --git a/src/game_log.rs b/src/gamelog.rs similarity index 100% rename from src/game_log.rs rename to src/gamelog.rs diff --git a/src/game_log/builder.rs b/src/gamelog/builder.rs similarity index 67% rename from src/game_log/builder.rs rename to src/gamelog/builder.rs index 69c28d3..bcfd68a 100644 --- a/src/game_log/builder.rs +++ b/src/gamelog/builder.rs @@ -15,6 +15,22 @@ pub fn line(text: T) -> Logger { Logger::new().append(text) } +/// Convenience method to create a new [`Logger`] and +/// immediately append text of the given color +pub fn color_line(color: RGB, text: T) -> Logger { + Logger::new().append_color(color, text) +} + +/// Convenience function to log a simple line of white text +pub fn log_line(text: T) { + line(text).log(); +} + +/// Convenience function to log a line of one color +pub fn log_color_line(color: RGB, text: T) { + color_line(color, text).log(); +} + impl Logger { pub fn new() -> Self { Logger { @@ -52,10 +68,15 @@ impl Logger { } /// Convenience method to append text with a new color - pub fn append_color(mut self, color: RGB, text: T) -> Self { + pub fn append_color(self, color: RGB, text: T) -> Self { self.color(color).append(text) } + /// Convenience method to append white text after the text has had a different color + pub fn append_white(self, text: T) -> Self { + self.append_color(colors::WHITE, text) + } + /// Append the current line to the log output pub fn log(self) { append_entry(self.fragments); diff --git a/src/game_log/logstore.rs b/src/gamelog/logstore.rs similarity index 97% rename from src/game_log/logstore.rs rename to src/gamelog/logstore.rs index d700be9..fe6322f 100644 --- a/src/game_log/logstore.rs +++ b/src/gamelog/logstore.rs @@ -8,6 +8,7 @@ lazy_static! { static ref LOG: Mutex>> = Mutex::new(Vec::new()); } +#[allow(dead_code)] pub fn append_fragment(fragment: LogFragment) { LOG.lock().unwrap().push(vec![fragment]); } diff --git a/src/gui.rs b/src/gui.rs index c94f65c..fc4d0f3 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -16,7 +16,7 @@ use crate::components::{ InBackpack, KnownSpells, MagicItem, MagicItemClass, Name, ObfuscatedName, Pools, StatusEffect, Viewshed, Weapon, }; -use crate::{camera, colors, game_log, Map, MasterDungeonMap, State}; +use crate::{camera, colors, gamelog, Map, MasterDungeonMap, State}; pub fn get_item_color(ecs: &World, item: Entity) -> RGB { let dm = ecs.fetch::(); @@ -326,7 +326,9 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { // Draw the log let mut block = TextBlock::new(1, 46, 79, 58); - block.print(&game_log::log_display()); + block + .print(&gamelog::log_display()) + .expect("Failed to print game log."); block.render(&mut ::rltk::BACKEND_INTERNAL.lock().consoles[0].console); draw_tooltips(ecs, ctx); diff --git a/src/hunger_system.rs b/src/hunger_system.rs index a4d5331..04394a4 100644 --- a/src/hunger_system.rs +++ b/src/hunger_system.rs @@ -1,8 +1,9 @@ use ::specs::prelude::*; +use crate::colors; use crate::components::{HungerClock, HungerState, MyTurn}; use crate::effects::{add_effect, EffectType, Targets}; -use crate::game_log::GameLog; +use crate::gamelog::log_color_line; pub struct HungerSystem {} @@ -12,12 +13,11 @@ impl<'a> System<'a> for HungerSystem { Entities<'a>, WriteStorage<'a, HungerClock>, ReadExpect<'a, Entity>, // The player - WriteExpect<'a, GameLog>, ReadStorage<'a, MyTurn>, ); fn run(&mut self, data: Self::SystemData) { - let (entities, mut hunger_clock, player_entity, mut log, turns) = data; + let (entities, mut hunger_clock, player_entity, turns) = data; for (entity, mut clock, _myturn) in (&entities, &mut hunger_clock, &turns).join() { clock.duration -= 1; @@ -29,7 +29,7 @@ impl<'a> System<'a> for HungerSystem { clock.duration = 200; if entity == *player_entity { - log.append("You are no longer well fed."); + log_color_line(colors::ORANGE, "You are no longer well fed"); } } HungerState::Normal => { @@ -37,7 +37,7 @@ impl<'a> System<'a> for HungerSystem { clock.duration = 200; if entity == *player_entity { - log.append("You are hungry."); + log_color_line(colors::ORANGE, "You are hungry."); } } HungerState::Hungry => { @@ -45,13 +45,13 @@ impl<'a> System<'a> for HungerSystem { clock.duration = 200; if entity == *player_entity { - log.append("You are starving!"); + log_color_line(colors::RED, "You are starving!"); } } HungerState::Starving => { // Inflict damage from hunger if entity == *player_entity { - log.append("Your hunger pangs are getting painful!"); + log_color_line(colors::RED, "Your hunger pangs are getting painful!"); } add_effect( diff --git a/src/inventory_system.rs b/src/inventory_system.rs index d39af02..e25cc37 100644 --- a/src/inventory_system.rs +++ b/src/inventory_system.rs @@ -1,16 +1,16 @@ mod collection_system; mod drop_system; +mod equip_use; mod identification_system; mod remove_system; -mod use_equip; mod use_system; use ::specs::prelude::*; pub use collection_system::ItemCollectionSystem; pub use drop_system::ItemDropSystem; +pub use equip_use::ItemEquipOnUse; pub use identification_system::ItemIdentificationSystem; pub use remove_system::ItemRemoveSystem; -pub use use_equip::ItemEquipOnUse; pub use use_system::{ItemUseSystem, SpellUseSystem}; use crate::components::{MagicItem, Name, ObfuscatedName}; diff --git a/src/inventory_system/collection_system.rs b/src/inventory_system/collection_system.rs index bf17e54..57f082c 100644 --- a/src/inventory_system/collection_system.rs +++ b/src/inventory_system/collection_system.rs @@ -4,8 +4,7 @@ use super::obfuscate_name; use crate::components::{ EquipmentChanged, InBackpack, MagicItem, Name, ObfuscatedName, Position, WantsToPickupItem, }; -use crate::game_log::GameLog; -use crate::MasterDungeonMap; +use crate::{colors, gamelog, MasterDungeonMap}; pub struct ItemCollectionSystem {} @@ -13,7 +12,6 @@ impl<'a> System<'a> for ItemCollectionSystem { #[allow(clippy::type_complexity)] type SystemData = ( ReadExpect<'a, Entity>, - WriteExpect<'a, GameLog>, WriteStorage<'a, WantsToPickupItem>, WriteStorage<'a, Position>, ReadStorage<'a, Name>, @@ -27,7 +25,6 @@ impl<'a> System<'a> for ItemCollectionSystem { fn run(&mut self, data: Self::SystemData) { let ( player_entity, - mut gamelog, mut wants_pickup, mut positions, names, @@ -53,10 +50,12 @@ impl<'a> System<'a> for ItemCollectionSystem { .expect("Unable to insert equipment change"); if pickup.collected_by == *player_entity { - gamelog.append(format!( - "You pick up the {}.", - obfuscate_name(pickup.item, &names, &magic_items, &obfuscated_names, &dm) - )); + gamelog::line("You pick up the") + .append_color( + colors::CYAN, + obfuscate_name(pickup.item, &names, &magic_items, &obfuscated_names, &dm), + ) + .log(); } } diff --git a/src/inventory_system/drop_system.rs b/src/inventory_system/drop_system.rs index 1f4360f..5c9cd7a 100644 --- a/src/inventory_system/drop_system.rs +++ b/src/inventory_system/drop_system.rs @@ -4,8 +4,7 @@ use super::obfuscate_name; use crate::components::{ EquipmentChanged, InBackpack, MagicItem, Name, ObfuscatedName, Position, WantsToDropItem, }; -use crate::game_log::GameLog; -use crate::MasterDungeonMap; +use crate::{colors, gamelog, MasterDungeonMap}; pub struct ItemDropSystem {} @@ -13,7 +12,6 @@ impl<'a> System<'a> for ItemDropSystem { #[allow(clippy::type_complexity)] type SystemData = ( ReadExpect<'a, Entity>, - WriteExpect<'a, GameLog>, Entities<'a>, WriteStorage<'a, WantsToDropItem>, ReadStorage<'a, Name>, @@ -28,7 +26,6 @@ impl<'a> System<'a> for ItemDropSystem { fn run(&mut self, data: Self::SystemData) { let ( player_entity, - mut gamelog, entities, mut wants_drop, names, @@ -65,10 +62,12 @@ impl<'a> System<'a> for ItemDropSystem { .expect("Unable to insert equipment change"); if entity == *player_entity { - gamelog.append(format!( - "You drop the {}.", - obfuscate_name(to_drop.item, &names, &magic_items, &obfuscated_names, &dm) - )); + gamelog::line("You drop the") + .append_color( + colors::CYAN, + obfuscate_name(to_drop.item, &names, &magic_items, &obfuscated_names, &dm), + ) + .log(); } } diff --git a/src/inventory_system/use_equip.rs b/src/inventory_system/equip_use.rs similarity index 88% rename from src/inventory_system/use_equip.rs rename to src/inventory_system/equip_use.rs index ad0c18f..d3c0643 100644 --- a/src/inventory_system/use_equip.rs +++ b/src/inventory_system/equip_use.rs @@ -4,7 +4,7 @@ use crate::components::{ CursedItem, EquipmentChanged, Equippable, Equipped, IdentifiedItem, InBackpack, Name, WantsToUseItem, }; -use crate::GameLog; +use crate::{colors, gamelog}; pub struct ItemEquipOnUse {} @@ -12,7 +12,6 @@ impl<'a> System<'a> for ItemEquipOnUse { #[allow(clippy::type_complexity)] type SystemData = ( ReadExpect<'a, Entity>, - WriteExpect<'a, GameLog>, Entities<'a>, WriteStorage<'a, WantsToUseItem>, ReadStorage<'a, Name>, @@ -27,7 +26,6 @@ impl<'a> System<'a> for ItemEquipOnUse { fn run(&mut self, data: Self::SystemData) { let ( player_entity, - mut gamelog, entities, mut wants_use, names, @@ -48,18 +46,19 @@ impl<'a> System<'a> for ItemEquipOnUse { // Remove any items the target has in the item's slot let mut can_equip = true; - let mut log_entries: Vec = Vec::new(); let mut to_unequip = Vec::new(); for (item_entity, already_equipped, name) in (&entities, &equipped, &names).join() { if already_equipped.owner == target && already_equipped.slot == target_slot { if cursed.get(item_entity).is_some() { + gamelog::line("You cannot un-equip") + .append_color(colors::CYAN, &name.name) + .append_white("- it is cursed!") + .log(); can_equip = false; - gamelog - .append(format!("You cannot un-equip {}, it is cursed.", name.name)) } else { to_unequip.push(item_entity); if target == *player_entity { - log_entries.push(format!("You un-equip {}.", name.name)); + gamelog::log_line(format!("You un-equip {}.", name.name)); } } } @@ -85,10 +84,6 @@ impl<'a> System<'a> for ItemEquipOnUse { .expect("Unable to move equipped item to backpack."); } - for entry in log_entries.iter() { - gamelog.append(entry); - } - // Wield the item equipped .insert( @@ -101,7 +96,7 @@ impl<'a> System<'a> for ItemEquipOnUse { .expect("Unable to equip item"); backpack.remove(useitem.item); if target == *player_entity { - gamelog.append(format!( + gamelog::log_line(format!( "You equip {}.", names.get(useitem.item).unwrap().name )); diff --git a/src/inventory_system/remove_system.rs b/src/inventory_system/remove_system.rs index 2332ac5..d48b629 100644 --- a/src/inventory_system/remove_system.rs +++ b/src/inventory_system/remove_system.rs @@ -1,7 +1,7 @@ use ::specs::prelude::*; use crate::components::{CursedItem, Equipped, InBackpack, Name, WantsToRemoveItem}; -use crate::GameLog; +use crate::{colors, gamelog}; pub struct ItemRemoveSystem {} @@ -13,20 +13,18 @@ impl<'a> System<'a> for ItemRemoveSystem { WriteStorage<'a, Equipped>, WriteStorage<'a, InBackpack>, ReadStorage<'a, CursedItem>, - WriteExpect<'a, GameLog>, ReadStorage<'a, Name>, ); fn run(&mut self, data: Self::SystemData) { - let (entities, mut wants_remove, mut equipped, mut backpack, cursed, mut gamelog, names) = - data; + let (entities, mut wants_remove, mut equipped, mut backpack, cursed, names) = data; for (entity, to_remove) in (&entities, &wants_remove).join() { if cursed.get(to_remove.item).is_some() { - gamelog.append(format!( - "You cannot remove {}, it is cursed", - names.get(to_remove.item).unwrap().name - )); + gamelog::line("You cannot remove") + .append_color(colors::CYAN, &names.get(to_remove.item).unwrap().name) + .append_white(" - it is cursed.") + .log(); continue; } diff --git a/src/main.rs b/src/main.rs index f4cd607..62beca8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ mod colors; mod components; mod damage_system; mod effects; -mod game_log; +mod gamelog; mod gamesystem; mod gui; mod hunger_system; diff --git a/src/melee_combat_system.rs b/src/melee_combat_system.rs index 32975db..0bb0787 100644 --- a/src/melee_combat_system.rs +++ b/src/melee_combat_system.rs @@ -1,14 +1,13 @@ use ::rltk::RandomNumberGenerator; use ::specs::prelude::*; -use crate::colors; use crate::components::{ Attributes, EquipmentSlot, Equipped, HungerClock, HungerState, Name, NaturalAttackDefense, Pools, Skill, Skills, WantsToMelee, Weapon, WeaponAttribute, Wearable, }; use crate::effects::{add_effect, EffectType, Targets}; -use crate::game_log::GameLog; use crate::gamesystem::skill_bonus; +use crate::{colors, gamelog}; pub struct MeleeCombatSystem {} @@ -16,7 +15,6 @@ impl<'a> System<'a> for MeleeCombatSystem { #[allow(clippy::type_complexity)] type SystemData = ( Entities<'a>, - WriteExpect<'a, GameLog>, WriteStorage<'a, WantsToMelee>, ReadStorage<'a, Name>, ReadStorage<'a, Attributes>, @@ -33,7 +31,6 @@ impl<'a> System<'a> for MeleeCombatSystem { fn run(&mut self, data: Self::SystemData) { let ( entities, - mut log, mut wants_melee, names, attributes, @@ -163,10 +160,13 @@ impl<'a> System<'a> for MeleeCombatSystem { target: wants_melee.target, }, ); - log.append(format!( - "{} hits {} for {} hp.", - &name.name, &target_name.name, damage - )); + gamelog::color_line(colors::YELLOW, &name.name) + .append_white("hits") + .append_color(colors::YELLOW, &target_name.name) + .append_white("for") + .append_color(colors::RED, format!("{}", damage)) + .append_white("hp.") + .log(); // Proc effects if let Some(chance) = &weapon_info.proc_chance { @@ -189,10 +189,11 @@ impl<'a> System<'a> for MeleeCombatSystem { } } else if natural_roll == 1 { // Natural 1 miss - log.append(format!( - "{} considers attacking {}, but misjudges the timing.", - name.name, target_name.name - )); + gamelog::color_line(colors::CYAN, &name.name) + .append_white("considers attacking") + .append_color(colors::CYAN, &target_name.name) + .append_white("but misjudges the timing!") + .log(); add_effect( None, EffectType::Particle { @@ -207,10 +208,11 @@ impl<'a> System<'a> for MeleeCombatSystem { ); } else { // Miss - log.append(format!( - "{} attacks {}, but can't connect", - name.name, target_name.name - )); + gamelog::color_line(colors::CYAN, &name.name) + .append_white("attacks") + .append_color(colors::CYAN, &target_name.name) + .append_white("but can't connect.") + .log(); add_effect( None, EffectType::Particle { diff --git a/src/player.rs b/src/player.rs index 6012447..0c699b3 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,6 +1,6 @@ use std::cmp::{max, min}; -use rltk::{DistanceAlg, Point, Rltk, VirtualKeyCode}; +use rltk::{DistanceAlg, Point, RandomNumberGenerator, Rltk, VirtualKeyCode}; use specs::prelude::*; use crate::components::{ @@ -8,9 +8,10 @@ use crate::components::{ HungerState, Item, Name, Player, Pools, Position, Renderable, Target, Vendor, Viewshed, WantsToMelee, WantsToPickupItem, WantsToShoot, }; -use crate::game_log::GameLog; use crate::raws::{self, Reaction, RAWS}; -use crate::{spatial, Map, RunState, State, TileType, VendorMode, WantsToCastSpell, Weapon}; +use crate::{ + colors, gamelog, spatial, Map, RunState, State, TileType, VendorMode, WantsToCastSpell, Weapon, +}; fn get_player_target_list(ecs: &mut World) -> Vec<(f32, Entity)> { let mut possible_targets = Vec::new(); @@ -68,7 +69,6 @@ fn fire_on_target(ecs: &mut World) -> RunState { let targets = ecs.write_storage::(); let entities = ecs.entities(); let mut current_target: Option = None; - let mut log = ecs.fetch_mut::(); for (e, _t) in (&entities, &targets).join() { current_target = Some(e); @@ -79,7 +79,9 @@ fn fire_on_target(ecs: &mut World) -> RunState { let mut shoot_store = ecs.write_storage::(); let names = ecs.read_storage::(); if let Some(name) = names.get(target) { - log.entries.push(format!("You fire at {}", name.name)); + gamelog::line("You fire at") + .append_color(colors::CYAN, &name.name) + .log(); } shoot_store .insert(*player_entity, WantsToShoot { target }) @@ -87,8 +89,7 @@ fn fire_on_target(ecs: &mut World) -> RunState { RunState::Ticking } else { - log.entries - .push("You don't have a target selected!".to_string()); + gamelog::log_line("You don't have a target selected!"); RunState::AwaitingInput } } @@ -269,10 +270,7 @@ pub fn try_next_level(ecs: &mut World) -> bool { if map.tiles[player_idx] == TileType::DownStairs { true } else { - let mut gamelog = ecs.fetch_mut::(); - gamelog - .entries - .push("There is no way down from here.".to_string()); + gamelog::log_line("There is no way down from here."); false } } @@ -285,10 +283,7 @@ pub fn try_previous_level(ecs: &mut World) -> bool { if map.tiles[player_idx] == TileType::UpStairs { true } else { - let mut gamelog = ecs.fetch_mut::(); - gamelog - .entries - .push("There is no way up from here.".to_string()); + gamelog::log_line("There is no way up from here."); false } } @@ -299,7 +294,6 @@ fn get_item(ecs: &mut World) { let entities = ecs.entities(); let items = ecs.read_storage::(); let positions = ecs.read_storage::(); - let mut gamelog = ecs.fetch_mut::(); let mut target_item: Option = None; for (item_entity, _item, position) in (&entities, &items, &positions).join() { @@ -309,9 +303,7 @@ fn get_item(ecs: &mut World) { } match target_item { - None => gamelog - .entries - .push("There is nothing here to pick up.".to_string()), + None => gamelog::log_line("There is nothing here to pick up."), Some(item) => { let mut pickup = ecs.write_storage::(); pickup @@ -365,7 +357,7 @@ fn skip_turn(ecs: &mut World) -> RunState { let pools = health_components.get_mut(*player_entity).unwrap(); pools.hit_points.current = i32::min(pools.hit_points.current + 1, pools.hit_points.max); - let mut rng = ecs.fetch_mut::<::rltk::RandomNumberGenerator>(); + let mut rng = ecs.fetch_mut::(); if rng.roll_dice(1, 6) == 1 { pools.mana.current = i32::min(pools.mana.current + 1, pools.mana.max); } @@ -454,8 +446,7 @@ fn use_spell_hotkey(gs: &mut State, key: i32) -> RunState { return RunState::Ticking; } } else { - let mut gamelog = gs.ecs.fetch_mut::(); - gamelog.append("You don't have enough mana to cast that!"); + gamelog::log_line("You don't have enough mana to cast that!"); } } diff --git a/src/ranged_combat_system.rs b/src/ranged_combat_system.rs index 07d48de..4f19e89 100644 --- a/src/ranged_combat_system.rs +++ b/src/ranged_combat_system.rs @@ -6,9 +6,8 @@ use crate::components::{ Pools, Position, Skill, Skills, WantsToShoot, Weapon, WeaponAttribute, Wearable, }; use crate::effects::{add_effect, EffectType, Targets}; -use crate::game_log::GameLog; use crate::gamesystem::skill_bonus; -use crate::{colors, Map}; +use crate::{colors, gamelog, Map}; pub struct RangedCombatSystem {} @@ -16,7 +15,6 @@ impl<'a> System<'a> for RangedCombatSystem { #[allow(clippy::type_complexity)] type SystemData = ( Entities<'a>, - WriteExpect<'a, GameLog>, WriteStorage<'a, WantsToShoot>, ReadStorage<'a, Name>, ReadStorage<'a, Attributes>, @@ -35,7 +33,6 @@ impl<'a> System<'a> for RangedCombatSystem { fn run(&mut self, data: Self::SystemData) { let ( entities, - mut log, mut wants_shoot, names, attributes, @@ -188,11 +185,13 @@ impl<'a> System<'a> for RangedCombatSystem { target: wants_shoot.target, }, ); - log.append(format!( - "{} hits {} for {} hp.", - &name.name, &target_name.name, damage - )); - + gamelog::color_line(colors::YELLOW, &name.name) + .append_white("hits") + .append_color(colors::YELLOW, &target_name.name) + .append_white("for") + .append_color(colors::RED, format!("{}", damage)) + .append_white("hp.") + .log(); // Proc effects if let Some(chance) = &weapon_info.proc_chance { if rng.roll_dice(1, 100) <= (chance * 100.0) as i32 { @@ -214,10 +213,11 @@ impl<'a> System<'a> for RangedCombatSystem { } } else if natural_roll == 1 { // Natural 1 miss - log.append(format!( - "{} considers attacking {}, but misjudges the timing.", - name.name, target_name.name - )); + gamelog::color_line(colors::CYAN, &name.name) + .append_white("considers attacking") + .append_color(colors::CYAN, &target_name.name) + .append_white("but misjudges the timing!") + .log(); add_effect( None, EffectType::Particle { @@ -232,10 +232,11 @@ impl<'a> System<'a> for RangedCombatSystem { ); } else { // Miss - log.append(format!( - "{} attacks {}, but can't connect", - name.name, target_name.name - )); + gamelog::color_line(colors::CYAN, &name.name) + .append_white("attacks") + .append_color(colors::CYAN, &target_name.name) + .append_white("but can't connect.") + .log(); add_effect( None, EffectType::Particle { diff --git a/src/state.rs b/src/state.rs index e49c050..6996feb 100644 --- a/src/state.rs +++ b/src/state.rs @@ -20,7 +20,9 @@ use crate::ranged_combat_system::RangedCombatSystem; use crate::raws::*; use crate::trigger_system::TriggerSystem; use crate::visibility_system::VisibilitySystem; -use crate::{ai, camera, damage_system, effects, game_log, player, saveload_system, spawner}; +use crate::{ + ai, camera, colors, damage_system, effects, gamelog, player, saveload_system, spawner, +}; /// Whether to show a visual representation of map generation pub const SHOW_MAPGEN_VISUALIZER: bool = false; @@ -122,8 +124,7 @@ impl State { self.generate_world_map(current_depth + offset, offset); // Notify the player - let mut gamelog = self.ecs.fetch_mut::(); - gamelog.append("You change level."); + gamelog::log_line("You change level."); } fn game_over_cleanup(&mut self) { @@ -164,8 +165,8 @@ impl State { } // Set up the game log - game_log::clear_log(); - game_log::line("Welcome to") + gamelog::clear_log(); + gamelog::line("Welcome to") .append_color(colors::CYAN, "Rusty Roguelike") .log(); } diff --git a/src/trigger_system.rs b/src/trigger_system.rs index 5cc1144..78b850c 100644 --- a/src/trigger_system.rs +++ b/src/trigger_system.rs @@ -2,8 +2,7 @@ use ::specs::prelude::*; use crate::components::{AreaOfEffect, EntityMoved, EntryTrigger, Name, Position}; use crate::effects::{add_effect, aoe_tiles, EffectType, Targets}; -use crate::game_log::GameLog; -use crate::{spatial, Map}; +use crate::{colors, gamelog, spatial, Map}; pub struct TriggerSystem {} @@ -16,21 +15,12 @@ impl<'a> System<'a> for TriggerSystem { ReadStorage<'a, EntryTrigger>, ReadStorage<'a, Name>, Entities<'a>, - WriteExpect<'a, GameLog>, ReadStorage<'a, AreaOfEffect>, ); fn run(&mut self, data: Self::SystemData) { - let ( - map, - mut entity_moved, - position, - entry_trigger, - names, - entities, - mut log, - area_of_effect, - ) = data; + let (map, mut entity_moved, position, entry_trigger, names, entities, area_of_effect) = + data; // Iterate the entities that moved and their final position for (entity, mut _entity_moved, pos) in (&entities, &mut entity_moved, &position).join() { @@ -44,7 +34,9 @@ impl<'a> System<'a> for TriggerSystem { Some(_trigger) => { // We triggered it if let Some(name) = names.get(entity_id) { - log.append(format!("{} triggers!", &name.name)); + gamelog::color_line(colors::RED, &name.name) + .append_white("triggers!") + .log(); } // Call the effects system diff --git a/src/visibility_system.rs b/src/visibility_system.rs index 284cc38..c2f93a0 100644 --- a/src/visibility_system.rs +++ b/src/visibility_system.rs @@ -2,8 +2,7 @@ use ::rltk::{field_of_view, Point, RandomNumberGenerator}; use ::specs::prelude::*; use crate::components::{BlocksVisibility, Hidden, Name}; -use crate::game_log::GameLog; -use crate::{spatial, Map, Player, Position, Viewshed}; +use crate::{colors, gamelog, spatial, Map, Player, Position, Viewshed}; pub struct VisibilitySystem {} @@ -17,7 +16,6 @@ impl<'a> System<'a> for VisibilitySystem { ReadStorage<'a, Player>, WriteStorage<'a, Hidden>, WriteExpect<'a, RandomNumberGenerator>, - WriteExpect<'a, GameLog>, ReadStorage<'a, Name>, ReadStorage<'a, BlocksVisibility>, ); @@ -31,7 +29,6 @@ impl<'a> System<'a> for VisibilitySystem { player, mut hidden, mut rng, - mut log, names, blocks_visibility, ) = data; @@ -70,7 +67,9 @@ impl<'a> System<'a> for VisibilitySystem { if rng.roll_dice(1, 24) == 1 { let name = names.get(e); if let Some(name) = name { - log.entries.push(format!("You spotted a {}.", &name.name)); + gamelog::line("You spotted:") + .append_color(colors::RED, &name.name) + .log(); } hidden.remove(e); }