Add event counting to game log, completing section 5.29

This commit is contained in:
Timothy Warren 2022-02-01 11:59:44 -05:00
parent 21c0601ebd
commit 83cab40c13
10 changed files with 126 additions and 33 deletions

View File

@ -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<Vec<crate::gamelog::LogFragment>>,
pub events: HashMap<String, i32>,
}

View File

@ -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::<Pools>();
let player_entity = ecs.fetch::<Entity>();
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(

View File

@ -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};

View File

@ -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

43
src/gamelog/events.rs Normal file
View File

@ -0,0 +1,43 @@
use std::collections::HashMap;
use std::sync::Mutex;
lazy_static! {
static ref EVENTS: Mutex<HashMap<String, i32>> = Mutex::new(HashMap::new());
}
pub fn clear_events() {
EVENTS.lock().unwrap().clear();
}
pub fn record_event<T: ToString>(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<T: ToString>(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<String, i32> {
EVENTS.lock().unwrap().clone()
}
pub fn load_events(events: HashMap<String, i32>) {
clear_events();
events.iter().for_each(|(k, v)| {
EVENTS.lock().unwrap().insert(k.to_string(), *v);
});
}

View File

@ -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,
}
}

View File

@ -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;

View File

@ -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())
}

View File

@ -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::<SimpleMarker<SerializeMe>>()
.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() {

View File

@ -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;