From 83cab40c13f17b77bbbefc15b9ea2405d7fd3acb Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Tue, 1 Feb 2022 11:59:44 -0500 Subject: [PATCH] Add event counting to game log, completing section 5.29 --- src/components/serialize.rs | 3 +++ src/effects/damage.rs | 9 +++++++ src/gamelog.rs | 2 ++ src/gamelog/builder.rs | 2 +- src/gamelog/events.rs | 43 ++++++++++++++++++++++++++++++ src/gui.rs | 53 +++++++++++++++++++++++++++++++++++++ src/gui/menu.rs | 28 -------------------- src/main.rs | 12 ++++++--- src/saveload_system.rs | 2 ++ src/state.rs | 5 ++++ 10 files changed, 126 insertions(+), 33 deletions(-) create mode 100644 src/gamelog/events.rs diff --git a/src/components/serialize.rs b/src/components/serialize.rs index 46dbe26..510989b 100644 --- a/src/components/serialize.rs +++ b/src/components/serialize.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use ::serde::{Deserialize, Serialize}; use ::specs::prelude::*; use ::specs_derive::*; @@ -19,4 +21,5 @@ pub struct SerializationHelper { pub struct DMSerializationHelper { pub map: MasterDungeonMap, pub log: Vec>, + pub events: HashMap, } diff --git a/src/effects/damage.rs b/src/effects/damage.rs index 1b8258d..af2a01f 100644 --- a/src/effects/damage.rs +++ b/src/effects/damage.rs @@ -11,6 +11,7 @@ use crate::{colors, gamelog, EquipmentChanged, Map, StatusEffect}; pub fn inflict_damage(ecs: &mut World, damage: &EffectSpawner, target: Entity) { let mut pools = ecs.write_storage::(); + let player_entity = ecs.fetch::(); if let Some(pool) = pools.get_mut(target) { if !pool.god_mode { if let Some(creator) = damage.creator { @@ -31,6 +32,14 @@ pub fn inflict_damage(ecs: &mut World, damage: &EffectSpawner, target: Entity) { }, Targets::Single { target }, ); + if target == *player_entity { + gamelog::record_event("Damage Taken", amount); + } + if let Some(creator) = damage.creator { + if creator == *player_entity { + gamelog::record_event("Damage Inflicted", amount); + } + } if pool.hit_points.current < 1 { add_effect( diff --git a/src/gamelog.rs b/src/gamelog.rs index 9b85008..fd39ded 100644 --- a/src/gamelog.rs +++ b/src/gamelog.rs @@ -2,11 +2,13 @@ //! //! Where the exploits of the current game are recorded mod builder; +mod events; mod logstore; use ::rltk::RGB; use ::serde::{Deserialize, Serialize}; pub use builder::*; +pub use events::*; use logstore::*; pub use logstore::{clear_log, clone_log, log_display, restore_log}; diff --git a/src/gamelog/builder.rs b/src/gamelog/builder.rs index 6f33534..bf32f36 100644 --- a/src/gamelog/builder.rs +++ b/src/gamelog/builder.rs @@ -81,7 +81,7 @@ impl Logger { pub fn damage(mut self, damage: i32) -> Self { self.fragments.push(LogFragment { color: colors::RED, - text: format!("{}", damage).to_string(), + text: format!("{}", damage), }); self diff --git a/src/gamelog/events.rs b/src/gamelog/events.rs new file mode 100644 index 0000000..3b3e0db --- /dev/null +++ b/src/gamelog/events.rs @@ -0,0 +1,43 @@ +use std::collections::HashMap; +use std::sync::Mutex; + +lazy_static! { + static ref EVENTS: Mutex> = Mutex::new(HashMap::new()); +} + +pub fn clear_events() { + EVENTS.lock().unwrap().clear(); +} + +pub fn record_event(event: T, n: i32) { + let event_name = event.to_string(); + let mut events_lock = EVENTS.lock(); + let events = events_lock.as_mut().unwrap(); + if let Some(e) = events.get_mut(&event_name) { + *e += n; + } else { + events.insert(event_name, n); + } +} + +pub fn get_event_count(event: T) -> i32 { + let event_name = event.to_string(); + let events_lock = EVENTS.lock(); + let events = events_lock.unwrap(); + if let Some(e) = events.get(&event_name) { + *e + } else { + 0 + } +} + +pub fn clone_events() -> HashMap { + EVENTS.lock().unwrap().clone() +} + +pub fn load_events(events: HashMap) { + clear_events(); + events.iter().for_each(|(k, v)| { + EVENTS.lock().unwrap().insert(k.to_string(), *v); + }); +} diff --git a/src/gui.rs b/src/gui.rs index fc4d0f3..11fa7f8 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -421,3 +421,56 @@ pub fn ranged_target( (ItemMenuResult::NoResponse, None) } + +pub fn game_over(ctx: &mut Rltk) -> GameOverResult { + ctx.print_color_centered(15, colors::YELLOW, colors::BLACK, "Your journey has ended!"); + ctx.print_color_centered( + 17, + colors::WHITE, + colors::BLACK, + "One day, we'll tell you all about how you did.", + ); + ctx.print_color_centered( + 18, + colors::WHITE, + colors::BLACK, + "That day, sadly, is not in this chapter...", + ); + + ctx.print_color_centered( + 19, + colors::WHITE, + colors::BLACK, + format!("You lived for {} turns.", gamelog::get_event_count("Turn")), + ); + ctx.print_color_centered( + 20, + colors::RED, + colors::BLACK, + &format!( + "You suffered {} points of damage.", + gamelog::get_event_count("Damage Taken") + ), + ); + ctx.print_color_centered( + 21, + colors::RED, + colors::BLACK, + &format!( + "You inflicted {} points of damage.", + gamelog::get_event_count("Damage Inflicted") + ), + ); + + ctx.print_color_centered( + 23, + colors::MAGENTA, + colors::BLACK, + "Press any key to return to the menu.", + ); + + match ctx.key { + None => GameOverResult::NoSelection, + Some(_) => GameOverResult::QuitToMenu, + } +} diff --git a/src/gui/menu.rs b/src/gui/menu.rs index 046801d..39f9d90 100644 --- a/src/gui/menu.rs +++ b/src/gui/menu.rs @@ -336,34 +336,6 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult { } } -pub fn game_over(ctx: &mut Rltk) -> GameOverResult { - ctx.print_color_centered(15, colors::YELLOW, colors::BLACK, "Your journey has ended!"); - ctx.print_color_centered( - 17, - colors::WHITE, - colors::BLACK, - "One day, we'll tell you all about how you did.", - ); - ctx.print_color_centered( - 18, - colors::WHITE, - colors::BLACK, - "That day, sadly, is not in this chapter...", - ); - - ctx.print_color_centered( - 20, - colors::MAGENTA, - colors::BLACK, - "Press any key to return to the menu.", - ); - - match ctx.key { - None => GameOverResult::NoSelection, - Some(_) => GameOverResult::QuitToMenu, - } -} - pub fn show_cheat_mode(_gs: &mut State, ctx: &mut Rltk) -> CheatMenuResult { let count = 4; let mut y = (25 - (count / 2)) as i32; diff --git a/src/main.rs b/src/main.rs index 62beca8..dc99908 100644 --- a/src/main.rs +++ b/src/main.rs @@ -164,6 +164,8 @@ fn register_components(state: &mut State) { /// * Creates the [`Player`](crate::spawner::player) /// * Generates the first [`map`](crate::state::State::generate_world_map) fn init_state() -> State { + use ::rltk::{Point, RandomNumberGenerator}; + let mut state = State::new(); register_components(&mut state); @@ -176,8 +178,8 @@ fn init_state() -> State { state.ecs.insert(MasterDungeonMap::new()); state.ecs.insert(Map::new(1, 64, 64, "New Map")); - state.ecs.insert(::rltk::Point::zero()); - state.ecs.insert(::rltk::RandomNumberGenerator::new()); + state.ecs.insert(Point::zero()); + state.ecs.insert(RandomNumberGenerator::new()); let player_entity = spawner::player(&mut state.ecs, 0, 0); state.ecs.insert(player_entity); @@ -193,10 +195,12 @@ fn init_state() -> State { /// The entry point fn main() -> ::rltk::BError { - let context = ::rltk::RltkBuilder::simple(80, 60) + use ::rltk::{main_loop, RltkBuilder}; + + let context = RltkBuilder::simple(80, 60) .unwrap() .with_title("Roguelike Tutorial") .build()?; - ::rltk::main_loop(context, init_state()) + main_loop(context, init_state()) } diff --git a/src/saveload_system.rs b/src/saveload_system.rs index ddfff4a..fe03b9d 100644 --- a/src/saveload_system.rs +++ b/src/saveload_system.rs @@ -44,6 +44,7 @@ pub fn save_game(ecs: &mut World) { .with(DMSerializationHelper { map: dungeon_master, log: crate::gamelog::clone_log(), + events: crate::gamelog::clone_events(), }) .marked::>() .build(); @@ -300,6 +301,7 @@ pub fn load_game(ecs: &mut World) { *dungeon_master = h.map.clone(); deleteme2 = Some(e); crate::gamelog::restore_log(&mut h.log.clone()); + crate::gamelog::load_events(h.events.clone()); } for (e, _p, pos) in (&entities, &player, &position).join() { diff --git a/src/state.rs b/src/state.rs index 6996feb..2d2e8d1 100644 --- a/src/state.rs +++ b/src/state.rs @@ -169,6 +169,8 @@ impl State { gamelog::line("Welcome to") .append_color(colors::CYAN, "Rusty Roguelike") .log(); + + gamelog::clear_events(); } } @@ -219,6 +221,9 @@ impl GameState for State { } RunState::AwaitingInput => { newrunstate = player_input(self, ctx); + if newrunstate != RunState::AwaitingInput { + crate::gamelog::record_event("Turn", 1); + } } RunState::Ticking => { let mut should_change_target = false;