Refactor all game log useage to use the new system

This commit is contained in:
Timothy Warren 2022-02-01 10:39:46 -05:00
parent 88fc0dbcea
commit a3f6c7b9d0
22 changed files with 163 additions and 164 deletions

View File

@ -6,8 +6,8 @@ use crate::components::{
AttributeBonus, Attributes, EquipmentChanged, Equipped, InBackpack, Item, Pools, Slow, AttributeBonus, Attributes, EquipmentChanged, Equipped, InBackpack, Item, Pools, Slow,
StatusEffect, StatusEffect,
}; };
use crate::game_log::GameLog;
use crate::gamesystem::attr_bonus; use crate::gamesystem::attr_bonus;
use crate::{colors, gamelog};
pub struct EncumbranceSystem {} pub struct EncumbranceSystem {}
@ -22,7 +22,6 @@ impl<'a> System<'a> for EncumbranceSystem {
WriteStorage<'a, Pools>, WriteStorage<'a, Pools>,
WriteStorage<'a, Attributes>, WriteStorage<'a, Attributes>,
ReadExpect<'a, Entity>, ReadExpect<'a, Entity>,
WriteExpect<'a, GameLog>,
ReadStorage<'a, AttributeBonus>, ReadStorage<'a, AttributeBonus>,
ReadStorage<'a, StatusEffect>, ReadStorage<'a, StatusEffect>,
ReadStorage<'a, Slow>, ReadStorage<'a, Slow>,
@ -38,7 +37,6 @@ impl<'a> System<'a> for EncumbranceSystem {
mut pools, mut pools,
mut attributes, mut attributes,
player, player,
mut gamelog,
attrbonus, attrbonus,
statuses, statuses,
slowed, slowed,
@ -133,7 +131,8 @@ impl<'a> System<'a> for EncumbranceSystem {
// Overburdened // Overburdened
pool.total_initiative_penalty += 4.0; pool.total_initiative_penalty += 4.0;
if *entity == *player { if *entity == *player {
gamelog.append( gamelog::log_color_line(
colors::ORANGE,
"You are overburdened, and suffering an initiative penalty.", "You are overburdened, and suffering an initiative penalty.",
); );
} }

View File

@ -2,14 +2,13 @@ use ::rltk::{Point, RandomNumberGenerator};
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::{MyTurn, Name, Quips, Viewshed}; use crate::components::{MyTurn, Name, Quips, Viewshed};
use crate::game_log::GameLog; use crate::{colors, gamelog};
pub struct QuipSystem {} pub struct QuipSystem {}
impl<'a> System<'a> for QuipSystem { impl<'a> System<'a> for QuipSystem {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
WriteExpect<'a, GameLog>,
WriteStorage<'a, Quips>, WriteStorage<'a, Quips>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
ReadStorage<'a, MyTurn>, ReadStorage<'a, MyTurn>,
@ -19,7 +18,7 @@ impl<'a> System<'a> for QuipSystem {
); );
fn run(&mut self, data: Self::SystemData) { 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() { for (quip, name, viewshed, _turn) in (&mut quips, &names, &viewsheds, &turns).join() {
if !quip.available.is_empty() 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 (rng.roll_dice(1, quip.available.len() as i32) - 1) as usize
}; };
gamelog.append(format!( gamelog::color_line(colors::YELLOW, &name.name)
"{} says \"{}\"", .append_white("says")
name.name, quip.available[quip_index] .append_color(colors::CYAN, &quip.available[quip_index])
)); .log();
quip.available.remove(quip_index); quip.available.remove(quip_index);
} }

View File

@ -5,9 +5,8 @@ use crate::components::{
AreaOfEffect, Equipped, InBackpack, LootTable, Name, OnDeath, Player, Pools, Position, AreaOfEffect, Equipped, InBackpack, LootTable, Name, OnDeath, Player, Pools, Position,
}; };
use crate::effects::*; use crate::effects::*;
use crate::game_log::GameLog;
use crate::raws::{self, SpawnType, RAWS}; use crate::raws::{self, SpawnType, RAWS};
use crate::{Map, RunState}; use crate::{colors, gamelog, Map, RunState};
pub fn delete_the_dead(ecs: &mut World) { pub fn delete_the_dead(ecs: &mut World) {
let mut dead: Vec<Entity> = Vec::new(); let mut dead: Vec<Entity> = Vec::new();
@ -18,14 +17,15 @@ pub fn delete_the_dead(ecs: &mut World) {
let players = ecs.read_storage::<Player>(); let players = ecs.read_storage::<Player>();
let names = ecs.read_storage::<Name>(); let names = ecs.read_storage::<Name>();
let entities = ecs.entities(); let entities = ecs.entities();
let mut log = ecs.write_resource::<GameLog>();
for (entity, stats) in (&entities, &combat_stats).join() { for (entity, stats) in (&entities, &combat_stats).join() {
if stats.hit_points.current < 1 { if stats.hit_points.current < 1 {
match players.get(entity) { match players.get(entity) {
None => { None => {
if let Some(victim_name) = names.get(entity) { 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) dead.push(entity)

View File

@ -7,7 +7,7 @@ use crate::components::{
Attributes, Confusion, DamageOverTime, Duration, Name, Player, Pools, SerializeMe, Skills, Slow, Attributes, Confusion, DamageOverTime, Duration, Name, Player, Pools, SerializeMe, Skills, Slow,
}; };
use crate::gamesystem::{mana_at_level, player_hp_at_level}; 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) { pub fn inflict_damage(ecs: &mut World, damage: &EffectSpawner, target: Entity) {
let mut pools = ecs.write_storage::<Pools>(); let mut pools = ecs.write_storage::<Pools>();
@ -69,7 +69,6 @@ pub fn death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
} }
if xp_gain != 0 || gold_gain != 0.0 { if xp_gain != 0 || gold_gain != 0.0 {
let mut log = ecs.fetch_mut::<GameLog>();
let mut player_stats = pools.get_mut(source).unwrap(); let mut player_stats = pools.get_mut(source).unwrap();
let mut player_attributes = attributes.get_mut(source).unwrap(); let mut player_attributes = attributes.get_mut(source).unwrap();
player_stats.xp += xp_gain; 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 { if player_stats.xp >= player_stats.level * 1000 {
// We've gone up a level! // We've gone up a level!
player_stats.level += 1; player_stats.level += 1;
log.append(format!( gamelog::color_line(colors::MAGENTA, "Congratulations, you are now level")
"Congratulations, you are now level {}", .append(format!("{}", player_stats.level))
player_stats.level .log();
));
// Improve a random attribute // Improve a random attribute
let mut rng = ecs.fetch_mut::<RandomNumberGenerator>(); let mut rng = ecs.fetch_mut::<RandomNumberGenerator>();
match rng.roll_dice(1, 4) { match rng.roll_dice(1, 4) {
1 => { 1 => {
player_attributes.might.base += 1; player_attributes.might.base += 1;
log.append("You feel stronger!"); gamelog::log_color_line(colors::GREEN, "You feel stronger!");
} }
2 => { 2 => {
player_attributes.fitness.base += 1; player_attributes.fitness.base += 1;
log.append("You feel healthier!"); gamelog::log_color_line(colors::GREEN, "You feel healthier!");
} }
3 => { 3 => {
player_attributes.quickness.base += 1; player_attributes.quickness.base += 1;
log.append("You feel quicker!"); gamelog::log_color_line(colors::GREEN, "You feel quicker!");
} }
_ => { _ => {
player_attributes.intelligence.base += 1; player_attributes.intelligence.base += 1;
log.append("You feel smarter!"); gamelog::log_color_line(colors::GREEN, "You feel smarter!");
} }
} }

View File

@ -11,18 +11,19 @@ use crate::components::{
}; };
use crate::effects::{aoe_tiles, entity_position, targeting}; use crate::effects::{aoe_tiles, entity_position, targeting};
use crate::raws::find_spell_entity; use crate::raws::find_spell_entity;
use crate::{colors, GameLog, Map, RunState}; use crate::{colors, gamelog, Map, RunState};
pub fn item_trigger(creator: Option<Entity>, item: Entity, targets: &Targets, ecs: &mut World) { pub fn item_trigger(creator: Option<Entity>, item: Entity, targets: &Targets, ecs: &mut World) {
// Check charges // Check charges
if let Some(c) = ecs.write_storage::<Consumable>().get_mut(item) { if let Some(c) = ecs.write_storage::<Consumable>().get_mut(item) {
if c.charges < 1 { if c.charges < 1 {
// Cancel // Cancel
let mut gamelog = ecs.fetch_mut::<GameLog>(); gamelog::color_line(
gamelog.append(format!( colors::CYAN,
"{} is out of charges!", &ecs.read_storage::<Name>().get(item).unwrap().name,
ecs.read_storage::<Name>().get(item).unwrap().name )
)); .append_white("is out of charges!")
.log();
return; return;
} else { } else {
@ -114,7 +115,6 @@ fn event_trigger(
ecs: &mut World, ecs: &mut World,
) -> bool { ) -> bool {
let mut did_something = false; let mut did_something = false;
let mut gamelog = ecs.fetch_mut::<GameLog>();
// Simple particle spawn // Simple particle spawn
if let Some(part) = ecs.read_storage::<SpawnParticleBurst>().get(entity) { if let Some(part) = ecs.read_storage::<SpawnParticleBurst>().get(entity) {
@ -158,7 +158,9 @@ fn event_trigger(
if ecs.read_storage::<ProvidesFood>().get(entity).is_some() { if ecs.read_storage::<ProvidesFood>().get(entity).is_some() {
add_effect(creator, EffectType::WellFed, targets.clone()); add_effect(creator, EffectType::WellFed, targets.clone());
let names = ecs.read_storage::<Name>(); let names = ecs.read_storage::<Name>();
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; did_something = true;
} }
@ -166,7 +168,7 @@ fn event_trigger(
// Magic mapper // Magic mapper
if ecs.read_storage::<MagicMapper>().get(entity).is_some() { if ecs.read_storage::<MagicMapper>().get(entity).is_some() {
let mut runstate = ecs.fetch_mut::<RunState>(); let mut runstate = ecs.fetch_mut::<RunState>();
gamelog.append("The map is revealed to you!"); gamelog::log_line("The map is revealed to you!");
*runstate = RunState::MagicMapReveal { row: 0 }; *runstate = RunState::MagicMapReveal { row: 0 };
did_something = true; did_something = true;
@ -200,9 +202,9 @@ fn event_trigger(
if ecs.read_storage::<TownPortal>().get(entity).is_some() { if ecs.read_storage::<TownPortal>().get(entity).is_some() {
let map = ecs.fetch::<Map>(); let map = ecs.fetch::<Map>();
if map.depth == 1 { 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 { } 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>(); let mut runstate = ecs.fetch_mut::<RunState>();
*runstate = RunState::TownPortal; *runstate = RunState::TownPortal;

View File

@ -15,6 +15,22 @@ pub fn line<T: ToString>(text: T) -> Logger {
Logger::new().append(text) Logger::new().append(text)
} }
/// Convenience method to create a new [`Logger`] and
/// immediately append text of the given color
pub fn color_line<T: ToString>(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<T: ToString>(text: T) {
line(text).log();
}
/// Convenience function to log a line of one color
pub fn log_color_line<T: ToString>(color: RGB, text: T) {
color_line(color, text).log();
}
impl Logger { impl Logger {
pub fn new() -> Self { pub fn new() -> Self {
Logger { Logger {
@ -52,10 +68,15 @@ impl Logger {
} }
/// Convenience method to append text with a new color /// Convenience method to append text with a new color
pub fn append_color<T: ToString>(mut self, color: RGB, text: T) -> Self { pub fn append_color<T: ToString>(self, color: RGB, text: T) -> Self {
self.color(color).append(text) self.color(color).append(text)
} }
/// Convenience method to append white text after the text has had a different color
pub fn append_white<T: ToString>(self, text: T) -> Self {
self.append_color(colors::WHITE, text)
}
/// Append the current line to the log output /// Append the current line to the log output
pub fn log(self) { pub fn log(self) {
append_entry(self.fragments); append_entry(self.fragments);

View File

@ -8,6 +8,7 @@ lazy_static! {
static ref LOG: Mutex<Vec<Vec<LogFragment>>> = Mutex::new(Vec::new()); static ref LOG: Mutex<Vec<Vec<LogFragment>>> = Mutex::new(Vec::new());
} }
#[allow(dead_code)]
pub fn append_fragment(fragment: LogFragment) { pub fn append_fragment(fragment: LogFragment) {
LOG.lock().unwrap().push(vec![fragment]); LOG.lock().unwrap().push(vec![fragment]);
} }

View File

@ -16,7 +16,7 @@ use crate::components::{
InBackpack, KnownSpells, MagicItem, MagicItemClass, Name, ObfuscatedName, Pools, StatusEffect, InBackpack, KnownSpells, MagicItem, MagicItemClass, Name, ObfuscatedName, Pools, StatusEffect,
Viewshed, Weapon, 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 { pub fn get_item_color(ecs: &World, item: Entity) -> RGB {
let dm = ecs.fetch::<crate::map::MasterDungeonMap>(); let dm = ecs.fetch::<crate::map::MasterDungeonMap>();
@ -326,7 +326,9 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
// Draw the log // Draw the log
let mut block = TextBlock::new(1, 46, 79, 58); 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); block.render(&mut ::rltk::BACKEND_INTERNAL.lock().consoles[0].console);
draw_tooltips(ecs, ctx); draw_tooltips(ecs, ctx);

View File

@ -1,8 +1,9 @@
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::colors;
use crate::components::{HungerClock, HungerState, MyTurn}; use crate::components::{HungerClock, HungerState, MyTurn};
use crate::effects::{add_effect, EffectType, Targets}; use crate::effects::{add_effect, EffectType, Targets};
use crate::game_log::GameLog; use crate::gamelog::log_color_line;
pub struct HungerSystem {} pub struct HungerSystem {}
@ -12,12 +13,11 @@ impl<'a> System<'a> for HungerSystem {
Entities<'a>, Entities<'a>,
WriteStorage<'a, HungerClock>, WriteStorage<'a, HungerClock>,
ReadExpect<'a, Entity>, // The player ReadExpect<'a, Entity>, // The player
WriteExpect<'a, GameLog>,
ReadStorage<'a, MyTurn>, ReadStorage<'a, MyTurn>,
); );
fn run(&mut self, data: Self::SystemData) { 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() { for (entity, mut clock, _myturn) in (&entities, &mut hunger_clock, &turns).join() {
clock.duration -= 1; clock.duration -= 1;
@ -29,7 +29,7 @@ impl<'a> System<'a> for HungerSystem {
clock.duration = 200; clock.duration = 200;
if entity == *player_entity { 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 => { HungerState::Normal => {
@ -37,7 +37,7 @@ impl<'a> System<'a> for HungerSystem {
clock.duration = 200; clock.duration = 200;
if entity == *player_entity { if entity == *player_entity {
log.append("You are hungry."); log_color_line(colors::ORANGE, "You are hungry.");
} }
} }
HungerState::Hungry => { HungerState::Hungry => {
@ -45,13 +45,13 @@ impl<'a> System<'a> for HungerSystem {
clock.duration = 200; clock.duration = 200;
if entity == *player_entity { if entity == *player_entity {
log.append("You are starving!"); log_color_line(colors::RED, "You are starving!");
} }
} }
HungerState::Starving => { HungerState::Starving => {
// Inflict damage from hunger // Inflict damage from hunger
if entity == *player_entity { 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( add_effect(

View File

@ -1,16 +1,16 @@
mod collection_system; mod collection_system;
mod drop_system; mod drop_system;
mod equip_use;
mod identification_system; mod identification_system;
mod remove_system; mod remove_system;
mod use_equip;
mod use_system; mod use_system;
use ::specs::prelude::*; use ::specs::prelude::*;
pub use collection_system::ItemCollectionSystem; pub use collection_system::ItemCollectionSystem;
pub use drop_system::ItemDropSystem; pub use drop_system::ItemDropSystem;
pub use equip_use::ItemEquipOnUse;
pub use identification_system::ItemIdentificationSystem; pub use identification_system::ItemIdentificationSystem;
pub use remove_system::ItemRemoveSystem; pub use remove_system::ItemRemoveSystem;
pub use use_equip::ItemEquipOnUse;
pub use use_system::{ItemUseSystem, SpellUseSystem}; pub use use_system::{ItemUseSystem, SpellUseSystem};
use crate::components::{MagicItem, Name, ObfuscatedName}; use crate::components::{MagicItem, Name, ObfuscatedName};

View File

@ -4,8 +4,7 @@ use super::obfuscate_name;
use crate::components::{ use crate::components::{
EquipmentChanged, InBackpack, MagicItem, Name, ObfuscatedName, Position, WantsToPickupItem, EquipmentChanged, InBackpack, MagicItem, Name, ObfuscatedName, Position, WantsToPickupItem,
}; };
use crate::game_log::GameLog; use crate::{colors, gamelog, MasterDungeonMap};
use crate::MasterDungeonMap;
pub struct ItemCollectionSystem {} pub struct ItemCollectionSystem {}
@ -13,7 +12,6 @@ impl<'a> System<'a> for ItemCollectionSystem {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
ReadExpect<'a, Entity>, ReadExpect<'a, Entity>,
WriteExpect<'a, GameLog>,
WriteStorage<'a, WantsToPickupItem>, WriteStorage<'a, WantsToPickupItem>,
WriteStorage<'a, Position>, WriteStorage<'a, Position>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
@ -27,7 +25,6 @@ impl<'a> System<'a> for ItemCollectionSystem {
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let ( let (
player_entity, player_entity,
mut gamelog,
mut wants_pickup, mut wants_pickup,
mut positions, mut positions,
names, names,
@ -53,10 +50,12 @@ impl<'a> System<'a> for ItemCollectionSystem {
.expect("Unable to insert equipment change"); .expect("Unable to insert equipment change");
if pickup.collected_by == *player_entity { if pickup.collected_by == *player_entity {
gamelog.append(format!( gamelog::line("You pick up the")
"You pick up the {}.", .append_color(
obfuscate_name(pickup.item, &names, &magic_items, &obfuscated_names, &dm) colors::CYAN,
)); obfuscate_name(pickup.item, &names, &magic_items, &obfuscated_names, &dm),
)
.log();
} }
} }

View File

@ -4,8 +4,7 @@ use super::obfuscate_name;
use crate::components::{ use crate::components::{
EquipmentChanged, InBackpack, MagicItem, Name, ObfuscatedName, Position, WantsToDropItem, EquipmentChanged, InBackpack, MagicItem, Name, ObfuscatedName, Position, WantsToDropItem,
}; };
use crate::game_log::GameLog; use crate::{colors, gamelog, MasterDungeonMap};
use crate::MasterDungeonMap;
pub struct ItemDropSystem {} pub struct ItemDropSystem {}
@ -13,7 +12,6 @@ impl<'a> System<'a> for ItemDropSystem {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
ReadExpect<'a, Entity>, ReadExpect<'a, Entity>,
WriteExpect<'a, GameLog>,
Entities<'a>, Entities<'a>,
WriteStorage<'a, WantsToDropItem>, WriteStorage<'a, WantsToDropItem>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
@ -28,7 +26,6 @@ impl<'a> System<'a> for ItemDropSystem {
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let ( let (
player_entity, player_entity,
mut gamelog,
entities, entities,
mut wants_drop, mut wants_drop,
names, names,
@ -65,10 +62,12 @@ impl<'a> System<'a> for ItemDropSystem {
.expect("Unable to insert equipment change"); .expect("Unable to insert equipment change");
if entity == *player_entity { if entity == *player_entity {
gamelog.append(format!( gamelog::line("You drop the")
"You drop the {}.", .append_color(
obfuscate_name(to_drop.item, &names, &magic_items, &obfuscated_names, &dm) colors::CYAN,
)); obfuscate_name(to_drop.item, &names, &magic_items, &obfuscated_names, &dm),
)
.log();
} }
} }

View File

@ -4,7 +4,7 @@ use crate::components::{
CursedItem, EquipmentChanged, Equippable, Equipped, IdentifiedItem, InBackpack, Name, CursedItem, EquipmentChanged, Equippable, Equipped, IdentifiedItem, InBackpack, Name,
WantsToUseItem, WantsToUseItem,
}; };
use crate::GameLog; use crate::{colors, gamelog};
pub struct ItemEquipOnUse {} pub struct ItemEquipOnUse {}
@ -12,7 +12,6 @@ impl<'a> System<'a> for ItemEquipOnUse {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
ReadExpect<'a, Entity>, ReadExpect<'a, Entity>,
WriteExpect<'a, GameLog>,
Entities<'a>, Entities<'a>,
WriteStorage<'a, WantsToUseItem>, WriteStorage<'a, WantsToUseItem>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
@ -27,7 +26,6 @@ impl<'a> System<'a> for ItemEquipOnUse {
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let ( let (
player_entity, player_entity,
mut gamelog,
entities, entities,
mut wants_use, mut wants_use,
names, names,
@ -48,18 +46,19 @@ impl<'a> System<'a> for ItemEquipOnUse {
// Remove any items the target has in the item's slot // Remove any items the target has in the item's slot
let mut can_equip = true; let mut can_equip = true;
let mut log_entries: Vec<String> = Vec::new();
let mut to_unequip = Vec::new(); let mut to_unequip = Vec::new();
for (item_entity, already_equipped, name) in (&entities, &equipped, &names).join() { for (item_entity, already_equipped, name) in (&entities, &equipped, &names).join() {
if already_equipped.owner == target && already_equipped.slot == target_slot { if already_equipped.owner == target && already_equipped.slot == target_slot {
if cursed.get(item_entity).is_some() { 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; can_equip = false;
gamelog
.append(format!("You cannot un-equip {}, it is cursed.", name.name))
} else { } else {
to_unequip.push(item_entity); to_unequip.push(item_entity);
if target == *player_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."); .expect("Unable to move equipped item to backpack.");
} }
for entry in log_entries.iter() {
gamelog.append(entry);
}
// Wield the item // Wield the item
equipped equipped
.insert( .insert(
@ -101,7 +96,7 @@ impl<'a> System<'a> for ItemEquipOnUse {
.expect("Unable to equip item"); .expect("Unable to equip item");
backpack.remove(useitem.item); backpack.remove(useitem.item);
if target == *player_entity { if target == *player_entity {
gamelog.append(format!( gamelog::log_line(format!(
"You equip {}.", "You equip {}.",
names.get(useitem.item).unwrap().name names.get(useitem.item).unwrap().name
)); ));

View File

@ -1,7 +1,7 @@
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::{CursedItem, Equipped, InBackpack, Name, WantsToRemoveItem}; use crate::components::{CursedItem, Equipped, InBackpack, Name, WantsToRemoveItem};
use crate::GameLog; use crate::{colors, gamelog};
pub struct ItemRemoveSystem {} pub struct ItemRemoveSystem {}
@ -13,20 +13,18 @@ impl<'a> System<'a> for ItemRemoveSystem {
WriteStorage<'a, Equipped>, WriteStorage<'a, Equipped>,
WriteStorage<'a, InBackpack>, WriteStorage<'a, InBackpack>,
ReadStorage<'a, CursedItem>, ReadStorage<'a, CursedItem>,
WriteExpect<'a, GameLog>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let (entities, mut wants_remove, mut equipped, mut backpack, cursed, mut gamelog, names) = let (entities, mut wants_remove, mut equipped, mut backpack, cursed, names) = data;
data;
for (entity, to_remove) in (&entities, &wants_remove).join() { for (entity, to_remove) in (&entities, &wants_remove).join() {
if cursed.get(to_remove.item).is_some() { if cursed.get(to_remove.item).is_some() {
gamelog.append(format!( gamelog::line("You cannot remove")
"You cannot remove {}, it is cursed", .append_color(colors::CYAN, &names.get(to_remove.item).unwrap().name)
names.get(to_remove.item).unwrap().name .append_white(" - it is cursed.")
)); .log();
continue; continue;
} }

View File

@ -10,7 +10,7 @@ mod colors;
mod components; mod components;
mod damage_system; mod damage_system;
mod effects; mod effects;
mod game_log; mod gamelog;
mod gamesystem; mod gamesystem;
mod gui; mod gui;
mod hunger_system; mod hunger_system;

View File

@ -1,14 +1,13 @@
use ::rltk::RandomNumberGenerator; use ::rltk::RandomNumberGenerator;
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::colors;
use crate::components::{ use crate::components::{
Attributes, EquipmentSlot, Equipped, HungerClock, HungerState, Name, NaturalAttackDefense, Attributes, EquipmentSlot, Equipped, HungerClock, HungerState, Name, NaturalAttackDefense,
Pools, Skill, Skills, WantsToMelee, Weapon, WeaponAttribute, Wearable, Pools, Skill, Skills, WantsToMelee, Weapon, WeaponAttribute, Wearable,
}; };
use crate::effects::{add_effect, EffectType, Targets}; use crate::effects::{add_effect, EffectType, Targets};
use crate::game_log::GameLog;
use crate::gamesystem::skill_bonus; use crate::gamesystem::skill_bonus;
use crate::{colors, gamelog};
pub struct MeleeCombatSystem {} pub struct MeleeCombatSystem {}
@ -16,7 +15,6 @@ impl<'a> System<'a> for MeleeCombatSystem {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
WriteExpect<'a, GameLog>,
WriteStorage<'a, WantsToMelee>, WriteStorage<'a, WantsToMelee>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
ReadStorage<'a, Attributes>, ReadStorage<'a, Attributes>,
@ -33,7 +31,6 @@ impl<'a> System<'a> for MeleeCombatSystem {
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let ( let (
entities, entities,
mut log,
mut wants_melee, mut wants_melee,
names, names,
attributes, attributes,
@ -163,10 +160,13 @@ impl<'a> System<'a> for MeleeCombatSystem {
target: wants_melee.target, target: wants_melee.target,
}, },
); );
log.append(format!( gamelog::color_line(colors::YELLOW, &name.name)
"{} hits {} for {} hp.", .append_white("hits")
&name.name, &target_name.name, damage .append_color(colors::YELLOW, &target_name.name)
)); .append_white("for")
.append_color(colors::RED, format!("{}", damage))
.append_white("hp.")
.log();
// Proc effects // Proc effects
if let Some(chance) = &weapon_info.proc_chance { if let Some(chance) = &weapon_info.proc_chance {
@ -189,10 +189,11 @@ impl<'a> System<'a> for MeleeCombatSystem {
} }
} else if natural_roll == 1 { } else if natural_roll == 1 {
// Natural 1 miss // Natural 1 miss
log.append(format!( gamelog::color_line(colors::CYAN, &name.name)
"{} considers attacking {}, but misjudges the timing.", .append_white("considers attacking")
name.name, target_name.name .append_color(colors::CYAN, &target_name.name)
)); .append_white("but misjudges the timing!")
.log();
add_effect( add_effect(
None, None,
EffectType::Particle { EffectType::Particle {
@ -207,10 +208,11 @@ impl<'a> System<'a> for MeleeCombatSystem {
); );
} else { } else {
// Miss // Miss
log.append(format!( gamelog::color_line(colors::CYAN, &name.name)
"{} attacks {}, but can't connect", .append_white("attacks")
name.name, target_name.name .append_color(colors::CYAN, &target_name.name)
)); .append_white("but can't connect.")
.log();
add_effect( add_effect(
None, None,
EffectType::Particle { EffectType::Particle {

View File

@ -1,6 +1,6 @@
use std::cmp::{max, min}; use std::cmp::{max, min};
use rltk::{DistanceAlg, Point, Rltk, VirtualKeyCode}; use rltk::{DistanceAlg, Point, RandomNumberGenerator, Rltk, VirtualKeyCode};
use specs::prelude::*; use specs::prelude::*;
use crate::components::{ use crate::components::{
@ -8,9 +8,10 @@ use crate::components::{
HungerState, Item, Name, Player, Pools, Position, Renderable, Target, Vendor, Viewshed, HungerState, Item, Name, Player, Pools, Position, Renderable, Target, Vendor, Viewshed,
WantsToMelee, WantsToPickupItem, WantsToShoot, WantsToMelee, WantsToPickupItem, WantsToShoot,
}; };
use crate::game_log::GameLog;
use crate::raws::{self, Reaction, RAWS}; 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)> { fn get_player_target_list(ecs: &mut World) -> Vec<(f32, Entity)> {
let mut possible_targets = Vec::new(); let mut possible_targets = Vec::new();
@ -68,7 +69,6 @@ fn fire_on_target(ecs: &mut World) -> RunState {
let targets = ecs.write_storage::<Target>(); let targets = ecs.write_storage::<Target>();
let entities = ecs.entities(); let entities = ecs.entities();
let mut current_target: Option<Entity> = None; let mut current_target: Option<Entity> = None;
let mut log = ecs.fetch_mut::<GameLog>();
for (e, _t) in (&entities, &targets).join() { for (e, _t) in (&entities, &targets).join() {
current_target = Some(e); current_target = Some(e);
@ -79,7 +79,9 @@ fn fire_on_target(ecs: &mut World) -> RunState {
let mut shoot_store = ecs.write_storage::<WantsToShoot>(); let mut shoot_store = ecs.write_storage::<WantsToShoot>();
let names = ecs.read_storage::<Name>(); let names = ecs.read_storage::<Name>();
if let Some(name) = names.get(target) { 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 shoot_store
.insert(*player_entity, WantsToShoot { target }) .insert(*player_entity, WantsToShoot { target })
@ -87,8 +89,7 @@ fn fire_on_target(ecs: &mut World) -> RunState {
RunState::Ticking RunState::Ticking
} else { } else {
log.entries gamelog::log_line("You don't have a target selected!");
.push("You don't have a target selected!".to_string());
RunState::AwaitingInput RunState::AwaitingInput
} }
} }
@ -269,10 +270,7 @@ pub fn try_next_level(ecs: &mut World) -> bool {
if map.tiles[player_idx] == TileType::DownStairs { if map.tiles[player_idx] == TileType::DownStairs {
true true
} else { } else {
let mut gamelog = ecs.fetch_mut::<GameLog>(); gamelog::log_line("There is no way down from here.");
gamelog
.entries
.push("There is no way down from here.".to_string());
false false
} }
} }
@ -285,10 +283,7 @@ pub fn try_previous_level(ecs: &mut World) -> bool {
if map.tiles[player_idx] == TileType::UpStairs { if map.tiles[player_idx] == TileType::UpStairs {
true true
} else { } else {
let mut gamelog = ecs.fetch_mut::<GameLog>(); gamelog::log_line("There is no way up from here.");
gamelog
.entries
.push("There is no way up from here.".to_string());
false false
} }
} }
@ -299,7 +294,6 @@ fn get_item(ecs: &mut World) {
let entities = ecs.entities(); let entities = ecs.entities();
let items = ecs.read_storage::<Item>(); let items = ecs.read_storage::<Item>();
let positions = ecs.read_storage::<Position>(); let positions = ecs.read_storage::<Position>();
let mut gamelog = ecs.fetch_mut::<GameLog>();
let mut target_item: Option<Entity> = None; let mut target_item: Option<Entity> = None;
for (item_entity, _item, position) in (&entities, &items, &positions).join() { for (item_entity, _item, position) in (&entities, &items, &positions).join() {
@ -309,9 +303,7 @@ fn get_item(ecs: &mut World) {
} }
match target_item { match target_item {
None => gamelog None => gamelog::log_line("There is nothing here to pick up."),
.entries
.push("There is nothing here to pick up.".to_string()),
Some(item) => { Some(item) => {
let mut pickup = ecs.write_storage::<WantsToPickupItem>(); let mut pickup = ecs.write_storage::<WantsToPickupItem>();
pickup pickup
@ -365,7 +357,7 @@ fn skip_turn(ecs: &mut World) -> RunState {
let pools = health_components.get_mut(*player_entity).unwrap(); let pools = health_components.get_mut(*player_entity).unwrap();
pools.hit_points.current = i32::min(pools.hit_points.current + 1, pools.hit_points.max); 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::<RandomNumberGenerator>();
if rng.roll_dice(1, 6) == 1 { if rng.roll_dice(1, 6) == 1 {
pools.mana.current = i32::min(pools.mana.current + 1, pools.mana.max); 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; return RunState::Ticking;
} }
} else { } else {
let mut gamelog = gs.ecs.fetch_mut::<GameLog>(); gamelog::log_line("You don't have enough mana to cast that!");
gamelog.append("You don't have enough mana to cast that!");
} }
} }

View File

@ -6,9 +6,8 @@ use crate::components::{
Pools, Position, Skill, Skills, WantsToShoot, Weapon, WeaponAttribute, Wearable, Pools, Position, Skill, Skills, WantsToShoot, Weapon, WeaponAttribute, Wearable,
}; };
use crate::effects::{add_effect, EffectType, Targets}; use crate::effects::{add_effect, EffectType, Targets};
use crate::game_log::GameLog;
use crate::gamesystem::skill_bonus; use crate::gamesystem::skill_bonus;
use crate::{colors, Map}; use crate::{colors, gamelog, Map};
pub struct RangedCombatSystem {} pub struct RangedCombatSystem {}
@ -16,7 +15,6 @@ impl<'a> System<'a> for RangedCombatSystem {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
WriteExpect<'a, GameLog>,
WriteStorage<'a, WantsToShoot>, WriteStorage<'a, WantsToShoot>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
ReadStorage<'a, Attributes>, ReadStorage<'a, Attributes>,
@ -35,7 +33,6 @@ impl<'a> System<'a> for RangedCombatSystem {
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let ( let (
entities, entities,
mut log,
mut wants_shoot, mut wants_shoot,
names, names,
attributes, attributes,
@ -188,11 +185,13 @@ impl<'a> System<'a> for RangedCombatSystem {
target: wants_shoot.target, target: wants_shoot.target,
}, },
); );
log.append(format!( gamelog::color_line(colors::YELLOW, &name.name)
"{} hits {} for {} hp.", .append_white("hits")
&name.name, &target_name.name, damage .append_color(colors::YELLOW, &target_name.name)
)); .append_white("for")
.append_color(colors::RED, format!("{}", damage))
.append_white("hp.")
.log();
// Proc effects // Proc effects
if let Some(chance) = &weapon_info.proc_chance { if let Some(chance) = &weapon_info.proc_chance {
if rng.roll_dice(1, 100) <= (chance * 100.0) as i32 { 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 { } else if natural_roll == 1 {
// Natural 1 miss // Natural 1 miss
log.append(format!( gamelog::color_line(colors::CYAN, &name.name)
"{} considers attacking {}, but misjudges the timing.", .append_white("considers attacking")
name.name, target_name.name .append_color(colors::CYAN, &target_name.name)
)); .append_white("but misjudges the timing!")
.log();
add_effect( add_effect(
None, None,
EffectType::Particle { EffectType::Particle {
@ -232,10 +232,11 @@ impl<'a> System<'a> for RangedCombatSystem {
); );
} else { } else {
// Miss // Miss
log.append(format!( gamelog::color_line(colors::CYAN, &name.name)
"{} attacks {}, but can't connect", .append_white("attacks")
name.name, target_name.name .append_color(colors::CYAN, &target_name.name)
)); .append_white("but can't connect.")
.log();
add_effect( add_effect(
None, None,
EffectType::Particle { EffectType::Particle {

View File

@ -20,7 +20,9 @@ use crate::ranged_combat_system::RangedCombatSystem;
use crate::raws::*; use crate::raws::*;
use crate::trigger_system::TriggerSystem; use crate::trigger_system::TriggerSystem;
use crate::visibility_system::VisibilitySystem; 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 /// Whether to show a visual representation of map generation
pub const SHOW_MAPGEN_VISUALIZER: bool = false; pub const SHOW_MAPGEN_VISUALIZER: bool = false;
@ -122,8 +124,7 @@ impl State {
self.generate_world_map(current_depth + offset, offset); self.generate_world_map(current_depth + offset, offset);
// Notify the player // Notify the player
let mut gamelog = self.ecs.fetch_mut::<GameLog>(); gamelog::log_line("You change level.");
gamelog.append("You change level.");
} }
fn game_over_cleanup(&mut self) { fn game_over_cleanup(&mut self) {
@ -164,8 +165,8 @@ impl State {
} }
// Set up the game log // Set up the game log
game_log::clear_log(); gamelog::clear_log();
game_log::line("Welcome to") gamelog::line("Welcome to")
.append_color(colors::CYAN, "Rusty Roguelike") .append_color(colors::CYAN, "Rusty Roguelike")
.log(); .log();
} }

View File

@ -2,8 +2,7 @@ use ::specs::prelude::*;
use crate::components::{AreaOfEffect, EntityMoved, EntryTrigger, Name, Position}; use crate::components::{AreaOfEffect, EntityMoved, EntryTrigger, Name, Position};
use crate::effects::{add_effect, aoe_tiles, EffectType, Targets}; use crate::effects::{add_effect, aoe_tiles, EffectType, Targets};
use crate::game_log::GameLog; use crate::{colors, gamelog, spatial, Map};
use crate::{spatial, Map};
pub struct TriggerSystem {} pub struct TriggerSystem {}
@ -16,21 +15,12 @@ impl<'a> System<'a> for TriggerSystem {
ReadStorage<'a, EntryTrigger>, ReadStorage<'a, EntryTrigger>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
Entities<'a>, Entities<'a>,
WriteExpect<'a, GameLog>,
ReadStorage<'a, AreaOfEffect>, ReadStorage<'a, AreaOfEffect>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let ( let (map, mut entity_moved, position, entry_trigger, names, entities, area_of_effect) =
map, data;
mut entity_moved,
position,
entry_trigger,
names,
entities,
mut log,
area_of_effect,
) = data;
// Iterate the entities that moved and their final position // Iterate the entities that moved and their final position
for (entity, mut _entity_moved, pos) in (&entities, &mut entity_moved, &position).join() { 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) => { Some(_trigger) => {
// We triggered it // We triggered it
if let Some(name) = names.get(entity_id) { 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 // Call the effects system

View File

@ -2,8 +2,7 @@ use ::rltk::{field_of_view, Point, RandomNumberGenerator};
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::{BlocksVisibility, Hidden, Name}; use crate::components::{BlocksVisibility, Hidden, Name};
use crate::game_log::GameLog; use crate::{colors, gamelog, spatial, Map, Player, Position, Viewshed};
use crate::{spatial, Map, Player, Position, Viewshed};
pub struct VisibilitySystem {} pub struct VisibilitySystem {}
@ -17,7 +16,6 @@ impl<'a> System<'a> for VisibilitySystem {
ReadStorage<'a, Player>, ReadStorage<'a, Player>,
WriteStorage<'a, Hidden>, WriteStorage<'a, Hidden>,
WriteExpect<'a, RandomNumberGenerator>, WriteExpect<'a, RandomNumberGenerator>,
WriteExpect<'a, GameLog>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
ReadStorage<'a, BlocksVisibility>, ReadStorage<'a, BlocksVisibility>,
); );
@ -31,7 +29,6 @@ impl<'a> System<'a> for VisibilitySystem {
player, player,
mut hidden, mut hidden,
mut rng, mut rng,
mut log,
names, names,
blocks_visibility, blocks_visibility,
) = data; ) = data;
@ -70,7 +67,9 @@ impl<'a> System<'a> for VisibilitySystem {
if rng.roll_dice(1, 24) == 1 { if rng.roll_dice(1, 24) == 1 {
let name = names.get(e); let name = names.get(e);
if let Some(name) = name { 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); hidden.remove(e);
} }