From 4f899d329ecbd8c1cd6876001d36ed20eb18bd11 Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Mon, 10 Jul 2023 12:48:56 +0100 Subject: [PATCH] initial --- src/damage_system.rs | 17 ++++++--- src/gamelog/builder.rs | 17 ++++++++- src/gamelog/logstore.rs | 1 + src/gamelog/mod.rs | 4 --- src/inventory_system.rs | 72 +++++++++++++++++++++++++++----------- src/main.rs | 7 ++-- src/melee_combat_system.rs | 33 +++++++++-------- src/monster_ai_system.rs | 14 ++++---- src/player.rs | 23 ++++++------ 9 files changed, 121 insertions(+), 67 deletions(-) diff --git a/src/damage_system.rs b/src/damage_system.rs index b46333f..633e708 100644 --- a/src/damage_system.rs +++ b/src/damage_system.rs @@ -1,4 +1,4 @@ -use super::{gamelog::GameLog, CombatStats, Entities, Item, Map, Name, Player, Position, SufferDamage}; +use super::{gamelog, CombatStats, Entities, Item, Map, Name, Player, Position, SufferDamage}; use specs::prelude::*; pub struct DamageSystem {} @@ -37,7 +37,6 @@ pub fn delete_the_dead(ecs: &mut World) { let names = ecs.read_storage::(); let items = ecs.read_storage::(); let entities = ecs.entities(); - let mut log = ecs.write_resource::(); for (entity, stats) in (&entities, &combat_stats).join() { if stats.hp < 1 { let player = players.get(entity); @@ -47,9 +46,19 @@ pub fn delete_the_dead(ecs: &mut World) { if let Some(victim_name) = victim_name { let item = items.get(entity); if let Some(_item) = item { - log.entries.push(format!("{} was destroyed!", &victim_name.name)); + gamelog::Logger::new() + .append("The") + .npc_name(&victim_name.name) + .colour(rltk::WHITE) + .append("was destroyed.") + .log(); } else { - log.entries.push(format!("The {} died!", &victim_name.name)); + gamelog::Logger::new() + .append("The") + .npc_name(&victim_name.name) + .colour(rltk::WHITE) + .append("died.") + .log(); } } dead.push(entity) diff --git a/src/gamelog/builder.rs b/src/gamelog/builder.rs index 0a7e481..3570041 100644 --- a/src/gamelog/builder.rs +++ b/src/gamelog/builder.rs @@ -22,6 +22,21 @@ impl Logger { } pub fn log(self) { - append_entry(self.fragments) + return append_entry(self.fragments); + } + + pub fn npc_name(mut self, text: T) -> Self { + self.fragments.push(LogFragment { colour: RGB::named(rltk::YELLOW), text: text.to_string() }); + return self; + } + + pub fn item_name(mut self, text: T) -> Self { + self.fragments.push(LogFragment { colour: RGB::named(rltk::CYAN), text: text.to_string() }); + return self; + } + + pub fn damage(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/gamelog/logstore.rs b/src/gamelog/logstore.rs index 02afbf0..7ff1015 100644 --- a/src/gamelog/logstore.rs +++ b/src/gamelog/logstore.rs @@ -6,6 +6,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/gamelog/mod.rs b/src/gamelog/mod.rs index def0086..31beb4f 100644 --- a/src/gamelog/mod.rs +++ b/src/gamelog/mod.rs @@ -6,10 +6,6 @@ mod logstore; use logstore::*; pub use logstore::{clear_log, log_display}; -pub struct GameLog { - pub entries: Vec, -} - pub struct LogFragment { pub colour: RGB, pub text: String, diff --git a/src/inventory_system.rs b/src/inventory_system.rs index b516a25..56e7585 100644 --- a/src/inventory_system.rs +++ b/src/inventory_system.rs @@ -1,6 +1,6 @@ use super::{ - gamelog::GameLog, CombatStats, Confusion, Consumable, Cursed, Destructible, InBackpack, InflictsDamage, - MagicMapper, Map, Name, ParticleBuilder, Point, Position, ProvidesHealing, RunState, SufferDamage, WantsToDropItem, + gamelog, CombatStats, Confusion, Consumable, Cursed, Destructible, InBackpack, InflictsDamage, MagicMapper, Map, + Name, ParticleBuilder, Point, Position, ProvidesHealing, RunState, SufferDamage, WantsToDropItem, WantsToPickupItem, WantsToUseItem, AOE, DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME, }; use specs::prelude::*; @@ -11,7 +11,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>, @@ -19,14 +18,17 @@ impl<'a> System<'a> for ItemCollectionSystem { ); fn run(&mut self, data: Self::SystemData) { - let (player_entity, mut gamelog, mut wants_pickup, mut positions, names, mut backpack) = data; + let (player_entity, mut wants_pickup, mut positions, names, mut backpack) = data; for pickup in wants_pickup.join() { positions.remove(pickup.item); backpack.insert(pickup.item, InBackpack { owner: pickup.collected_by }).expect("Unable to pickup item."); if pickup.collected_by == *player_entity { - gamelog.entries.push(format!("You pick up the {}.", names.get(pickup.item).unwrap().name)); + gamelog::Logger::new() + .append("You pick up the") + .item_name(format!("{}.", &names.get(pickup.item).unwrap().name)) + .log(); } } @@ -39,7 +41,6 @@ impl<'a> System<'a> for ItemUseSystem { #[allow(clippy::type_complexity)] type SystemData = ( ReadExpect<'a, Entity>, - WriteExpect<'a, GameLog>, ReadExpect<'a, Map>, Entities<'a>, WriteStorage<'a, WantsToUseItem>, @@ -62,7 +63,6 @@ impl<'a> System<'a> for ItemUseSystem { fn run(&mut self, data: Self::SystemData) { let ( player_entity, - mut gamelog, map, entities, mut wants_to_use, @@ -89,7 +89,7 @@ impl<'a> System<'a> for ItemUseSystem { let is_cursed = cursed_items.get(wants_to_use.item); - gamelog.entries.push(format!("You use the {}.", item_being_used.name)); + gamelog::Logger::new().append("You use the").item_name(format!("{}.", &item_being_used.name)).log(); // TARGETING let mut targets: Vec = Vec::new(); @@ -117,7 +117,12 @@ impl<'a> System<'a> for ItemUseSystem { if let Some(pos) = pos { target = Point::new(pos.x, pos.y); } - gamelog.entries.push(format!("The {} disobeys!", item_being_used.name)); + gamelog::Logger::new() + .append("The") + .item_name(&item_being_used.name) + .colour(rltk::WHITE) + .append("disobeys!") + .log(); } } // AOE @@ -153,7 +158,13 @@ impl<'a> System<'a> for ItemUseSystem { if let Some(stats) = stats { stats.hp = i32::min(stats.max_hp, stats.hp + heal.amount); if entity == *player_entity { - gamelog.entries.push(format!("Quaffing, you heal {} hp.", heal.amount)); + gamelog::Logger::new() + .append("Quaffing, you heal") + .colour(rltk::GREEN) + .append(heal.amount) + .colour(rltk::WHITE) + .append("hit points.") + .log(); } let pos = positions.get(entity); if let Some(pos) = pos { @@ -194,14 +205,25 @@ impl<'a> System<'a> for ItemUseSystem { None => { SufferDamage::new_damage(&mut suffer_damage, *mob, damage.amount); if entity == *player_entity { - gamelog.entries.push(format!( - "{} takes {} damage from the {}!", - entity_name.name, damage.amount, item_being_used.name - )); + gamelog::Logger::new() + .append("The") + .npc_name(&entity_name.name) + .colour(rltk::WHITE) + .append("takes") + .damage(damage.amount) + .colour(rltk::WHITE) + .append("damage from the") + .item_name(format!("{}.", &item_being_used.name)) + .log(); } } Some(_destructible) => { - gamelog.entries.push(format!("{} is destroyed!", entity_name.name)); + gamelog::Logger::new() + .append("The") + .item_name(&entity_name.name) + .colour(rltk::WHITE) + .append("is destroyed!") + .log(); entities.delete(*mob).expect("Delete failed"); } } @@ -237,11 +259,19 @@ impl<'a> System<'a> for ItemUseSystem { used_item = true; match is_cursed { None => { - gamelog.entries.push("You feel a sense of acuity to your surroundings.".to_string()); + gamelog::Logger::new() + .append("You feel") + .colour(rltk::GREEN) + .append("a sense of acuity towards your surroundings.") + .log(); *runstate = RunState::MagicMapReveal { row: 0, cursed: false }; } Some(_) => { - gamelog.entries.push("You forget where you just were!".to_string()); + gamelog::Logger::new() + .append("You") + .colour(rltk::RED) + .append("forget where you last were.") + .log(); *runstate = RunState::MagicMapReveal { row: 0, cursed: true }; } } @@ -269,7 +299,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>, @@ -278,7 +307,7 @@ impl<'a> System<'a> for ItemDropSystem { ); fn run(&mut self, data: Self::SystemData) { - let (player_entity, mut gamelog, entities, mut wants_drop, names, mut positions, mut backpack) = data; + let (player_entity, entities, mut wants_drop, names, mut positions, mut backpack) = data; for (entity, to_drop) in (&entities, &wants_drop).join() { let mut dropper_pos: Position = Position { x: 0, y: 0 }; @@ -293,7 +322,10 @@ impl<'a> System<'a> for ItemDropSystem { backpack.remove(to_drop.item); if entity == *player_entity { - gamelog.entries.push(format!("You drop the {}.", names.get(to_drop.item).unwrap().name)); + gamelog::Logger::new() + .append("You drop the") + .item_name(format!("{}.", &names.get(to_drop.item).unwrap().name)) + .log(); } } diff --git a/src/main.rs b/src/main.rs index 90aefef..1525678 100644 --- a/src/main.rs +++ b/src/main.rs @@ -157,8 +157,7 @@ impl State { } // Notify player, restore health up to a point. - let mut gamelog = self.ecs.fetch_mut::(); - gamelog.entries.push("You descend the stairwell, and take a moment to recover your strength.".to_string()); + gamelog::Logger::new().append("You descend the stairwell, and take a moment to gather your strength.").log(); let mut player_health_store = self.ecs.write_storage::(); let player_health = player_health_store.get_mut(*player_entity); if let Some(player_health) = player_health { @@ -431,9 +430,7 @@ fn main() -> rltk::BError { gs.ecs.insert(map); gs.ecs.insert(Point::new(player_x, player_y)); gs.ecs.insert(player_entity); - gs.ecs.insert(gamelog::GameLog { - entries: vec!["".to_string()], - }); + gamelog::clear_log(); gamelog::Logger::new() .append("Welcome!") diff --git a/src/melee_combat_system.rs b/src/melee_combat_system.rs index 5f6431d..2211ba9 100644 --- a/src/melee_combat_system.rs +++ b/src/melee_combat_system.rs @@ -1,4 +1,4 @@ -use super::{gamelog::GameLog, CombatStats, Name, ParticleBuilder, Position, SufferDamage, WantsToMelee}; +use super::{gamelog, CombatStats, Name, ParticleBuilder, Position, SufferDamage, WantsToMelee}; use specs::prelude::*; pub struct MeleeCombatSystem {} @@ -6,7 +6,6 @@ pub struct MeleeCombatSystem {} impl<'a> System<'a> for MeleeCombatSystem { type SystemData = ( Entities<'a>, - WriteExpect<'a, GameLog>, WriteStorage<'a, WantsToMelee>, ReadStorage<'a, Name>, ReadStorage<'a, CombatStats>, @@ -16,16 +15,8 @@ impl<'a> System<'a> for MeleeCombatSystem { ); fn run(&mut self, data: Self::SystemData) { - let ( - entities, - mut log, - mut wants_melee, - names, - combat_stats, - mut inflict_damage, - mut particle_builder, - positions, - ) = data; + let (entities, mut wants_melee, names, combat_stats, mut inflict_damage, mut particle_builder, positions) = + data; for (_entity, wants_melee, name, stats) in (&entities, &wants_melee, &names, &combat_stats).join() { if stats.hp <= 0 { @@ -51,9 +42,23 @@ impl<'a> System<'a> for MeleeCombatSystem { let damage = i32::max(0, stats.power - target_stats.defence); if damage == 0 { - log.entries.push(format!("{} is unable to hurt {}.", &name.name, &target_name.name)); + gamelog::Logger::new() + .append("The") + .npc_name(&name.name) + .colour(rltk::WHITE) + .append("attempts to strike") + .npc_name(&target_name.name) + .colour(rltk::WHITE) + .append("- but fails.") + .log(); } else { - log.entries.push(format!("{} hits {} for {} damage.", &name.name, &target_name.name, damage)); + gamelog::Logger::new() // hits the ! + .append("The") + .npc_name(&name.name) + .colour(rltk::WHITE) + .append("hits the") + .npc_name(format!("{}.", &target_name.name)) + .log(); SufferDamage::new_damage(&mut inflict_damage, wants_melee.target, damage); } } diff --git a/src/monster_ai_system.rs b/src/monster_ai_system.rs index 69dd326..1433673 100644 --- a/src/monster_ai_system.rs +++ b/src/monster_ai_system.rs @@ -1,6 +1,4 @@ -use super::{ - gamelog::GameLog, Confusion, Map, Monster, Name, ParticleBuilder, Position, RunState, Viewshed, WantsToMelee, -}; +use super::{gamelog, Confusion, Map, Monster, Name, ParticleBuilder, Position, RunState, Viewshed, WantsToMelee}; use rltk::Point; use specs::prelude::*; @@ -10,7 +8,6 @@ impl<'a> System<'a> for MonsterAI { #[allow(clippy::type_complexity)] type SystemData = ( WriteExpect<'a, Map>, - WriteExpect<'a, GameLog>, ReadExpect<'a, Point>, ReadExpect<'a, Entity>, ReadExpect<'a, RunState>, @@ -27,7 +24,6 @@ impl<'a> System<'a> for MonsterAI { fn run(&mut self, data: Self::SystemData) { let ( mut map, - mut gamelog, player_pos, player_entity, runstate, @@ -57,11 +53,15 @@ impl<'a> System<'a> for MonsterAI { let mut glyph = rltk::to_cp437('?'); if i_am_confused.turns < 1 { confused.remove(entity); - gamelog.entries.push(format!("{} snaps out of its confusion!", entity_name.name)); + gamelog::Logger::new() + .npc_name(&entity_name.name) + .colour(rltk::WHITE) + .append("snaps out of it.") + .log(); fg = rltk::RGB::named(rltk::MEDIUMSLATEBLUE); glyph = rltk::to_cp437('!'); } else { - gamelog.entries.push(format!("{} is confused.", entity_name.name)); + gamelog::Logger::new().npc_name(&entity_name.name).colour(rltk::WHITE).append("is confused.").log(); } particle_builder.request(pos.x, pos.y, fg, rltk::RGB::named(rltk::BLACK), glyph, 200.0); can_act = false; diff --git a/src/player.rs b/src/player.rs index 5a43b43..a031c5c 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,5 +1,5 @@ use super::{ - gamelog::GameLog, CombatStats, Item, Map, Monster, Name, Player, Position, RunState, State, TileType, Viewshed, + gamelog, CombatStats, Item, Map, Monster, Name, Player, Position, RunState, State, TileType, Viewshed, WantsToMelee, WantsToPickupItem, MAPHEIGHT, MAPWIDTH, }; use rltk::{Point, RandomNumberGenerator, Rltk, VirtualKeyCode}; @@ -48,8 +48,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) { } if tile_content != "You see " { tile_content.push_str("."); - let mut gamelog = ecs.write_resource::(); - gamelog.entries.push(tile_content); + gamelog::Logger::new().append(tile_content).log() } pos.x = min((MAPWIDTH as i32) - 1, max(0, pos.x + delta_x)); pos.y = min((MAPHEIGHT as i32) - 1, max(0, pos.y + delta_y)); @@ -67,7 +66,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() { @@ -77,7 +75,7 @@ fn get_item(ecs: &mut World) { } match target_item { - None => gamelog.entries.push("There is nothing to pick up.".to_string()), + None => gamelog::Logger::new().append("There is nothing to pick up.").log(), Some(item) => { let mut pickup = ecs.write_storage::(); pickup @@ -142,8 +140,7 @@ pub fn try_next_level(ecs: &mut World) -> bool { if map.tiles[player_idx] == TileType::DownStair { return true; } else { - let mut gamelog = ecs.fetch_mut::(); - gamelog.entries.push("You don't see a way down.".to_string()); + gamelog::Logger::new().append("You don't see a way down.").log(); return false; } } @@ -152,8 +149,6 @@ fn skip_turn(ecs: &mut World) -> RunState { let player_entity = ecs.fetch::(); let viewshed_components = ecs.read_storage::(); let monsters = ecs.read_storage::(); - let mut wait_message = "You wait a turn."; - let worldmap_resource = ecs.fetch::(); let mut can_heal = true; @@ -171,6 +166,7 @@ fn skip_turn(ecs: &mut World) -> RunState { } } + let mut did_heal = false; if can_heal { let mut health_components = ecs.write_storage::(); let player_hp = health_components.get_mut(*player_entity).unwrap(); @@ -178,12 +174,15 @@ fn skip_turn(ecs: &mut World) -> RunState { let roll = rng.roll_dice(1, 6); if (roll == 6) && player_hp.hp < player_hp.max_hp { player_hp.hp += 1; - wait_message = "You wait a turn, and recover a hit point."; + did_heal = true; } } - let mut gamelog = ecs.fetch_mut::(); - gamelog.entries.push(wait_message.to_string()); + if did_heal { + gamelog::Logger::new().append("You wait a turn, and").colour(rltk::GREEN).append("recover a hit point.").log(); + } else { + gamelog::Logger::new().append("You wait a turn.").log(); + } return RunState::PlayerTurn; }