significant events in morgue file, better event logging

This commit is contained in:
Llywelwyn 2023-08-25 22:43:50 +01:00
parent de5dacb2ba
commit 738484436b
38 changed files with 246 additions and 102 deletions

View file

@ -1,7 +1,7 @@
use crate::{ gamelog, Attributes, Burden, EquipmentChanged, Equipped, InBackpack, Item, Pools }; use crate::{ gamelog, Attributes, Burden, EquipmentChanged, Equipped, InBackpack, Item, Pools };
use specs::prelude::*; use specs::prelude::*;
use std::collections::HashMap; use std::collections::HashMap;
use crate::config::entity::CARRY_CAPACITY_PER_STRENGTH; use crate::data::entity::CARRY_CAPACITY_PER_STRENGTH;
pub struct EncumbranceSystem {} pub struct EncumbranceSystem {}

View file

@ -1,8 +1,9 @@
use crate::config::entity::*; use crate::data::entity::*;
use crate::{ Burden, BurdenLevel, Clock, Energy, Name, Position, RunState, TakingTurn }; use crate::{ Burden, BurdenLevel, Clock, Energy, Name, Position, RunState, TakingTurn };
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
use crate::config::CONFIG; use crate::config::CONFIG;
use crate::data::events::*;
pub struct EnergySystem {} pub struct EnergySystem {}
@ -50,10 +51,10 @@ impl<'a> System<'a> for EnergySystem {
if energy.current >= TURN_COST { if energy.current >= TURN_COST {
turns.insert(entity, TakingTurn {}).expect("Unable to insert turn for turn counter."); turns.insert(entity, TakingTurn {}).expect("Unable to insert turn for turn counter.");
energy.current -= TURN_COST; energy.current -= TURN_COST;
crate::gamelog::record_event("turns", 1); crate::gamelog::record_event(EVENT::TURN(1));
// Handle spawning mobs each turn // Handle spawning mobs each turn
if CONFIG.logging.log_ticks { if CONFIG.logging.log_ticks {
console::log(format!("===== TURN {} =====", crate::gamelog::get_event_count("turns"))); console::log(format!("===== TURN {} =====", crate::gamelog::get_event_count(EVENT::COUNT_TURN)));
} }
} }
} }

View file

@ -11,6 +11,7 @@ use crate::{
TakingTurn, TakingTurn,
}; };
use specs::prelude::*; use specs::prelude::*;
use crate::data::events::*;
pub struct RegenSystem {} pub struct RegenSystem {}
@ -47,14 +48,14 @@ impl<'a> System<'a> for RegenSystem {
return; return;
} }
// Monster HP regen // Monster HP regen
let current_turn = gamelog::get_event_count("turns"); let current_turn = gamelog::get_event_count(EVENT::COUNT_TURN);
if current_turn % MONSTER_HP_REGEN_TURN == 0 { if current_turn % MONSTER_HP_REGEN_TURN == 0 {
for (_e, _p, pool, _player) in (&entities, &positions, &mut pools, !&player).join() { for (_e, _p, pool, _player) in (&entities, &positions, &mut pools, !&player).join() {
try_hp_regen_tick(pool, MONSTER_HP_REGEN_PER_TICK); try_hp_regen_tick(pool, MONSTER_HP_REGEN_PER_TICK);
} }
} }
// Player HP regen // Player HP regen
let level = gamelog::get_event_count("player_level"); let level = gamelog::get_event_count(EVENT::COUNT_LEVEL);
if current_turn % get_player_hp_regen_turn(level) == 0 { if current_turn % get_player_hp_regen_turn(level) == 0 {
for (_e, _p, pool, _player) in (&entities, &positions, &mut pools, &player).join() { for (_e, _p, pool, _player) in (&entities, &positions, &mut pools, &player).join() {
try_hp_regen_tick(pool, get_player_hp_regen_per_tick(level)); try_hp_regen_tick(pool, get_player_hp_regen_per_tick(level));

View file

@ -10,6 +10,7 @@ use crate::{
}; };
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
use crate::data::events::*;
pub struct TurnStatusSystem {} pub struct TurnStatusSystem {}
@ -78,7 +79,7 @@ impl<'a> System<'a> for TurnStatusSystem {
.colour(WHITE) .colour(WHITE)
.append("are confused!"); .append("are confused!");
log = true; log = true;
gamelog::record_event("player_confused", 1); gamelog::record_event(EVENT::PLAYER_CONFUSED(1));
} else { } else {
logger = logger logger = logger
.append("The") .append("The")

View file

@ -71,7 +71,7 @@ pub fn render_camera(ecs: &World, ctx: &mut Rltk) {
if map.visible_tiles[idx] { if map.visible_tiles[idx] {
draw = true; draw = true;
} else { } else {
fg = fg.mul(crate::config::visuals::NON_VISIBLE_MULTIPLIER); fg = fg.mul(crate::data::visuals::NON_VISIBLE_MULTIPLIER);
// We don't darken BG, because get_tile_renderables_for_id handles this. // We don't darken BG, because get_tile_renderables_for_id handles this.
} }

View file

@ -21,7 +21,8 @@ pub struct SerializationHelper {
pub struct DMSerializationHelper { pub struct DMSerializationHelper {
pub map: super::map::MasterDungeonMap, pub map: super::map::MasterDungeonMap,
pub log: Vec<Vec<crate::gamelog::LogFragment>>, pub log: Vec<Vec<crate::gamelog::LogFragment>>,
pub events: HashMap<String, i32>, pub event_counts: HashMap<String, i32>,
pub events: HashMap<u32, Vec<String>>,
} }
#[derive(Component, ConvertSaveload, Clone)] #[derive(Component, ConvertSaveload, Clone)]

View file

@ -1,21 +0,0 @@
// DEFAULT THEME
#[allow(dead_code)]
pub const WALL_GLYPH: char = '#';
pub const FLOOR_GLYPH: char = '.';
pub const DOWN_STAIR_GLYPH: char = '>';
pub const UP_STAIR_GLYPH: char = '<';
pub const WOOD_FLOOR_GLYPH: char = '.';
pub const FENCE_GLYPH: char = '=';
pub const BRIDGE_GLYPH: char = '.';
pub const GRAVEL_GLYPH: char = ';';
pub const ROAD_GLYPH: char = '.';
pub const GRASS_GLYPH: char = '"';
pub const FOLIAGE_GLYPH: char = ':';
pub const HEAVY_FOLIAGE_GLYPH: char = ';';
pub const SAND_GLYPH: char = '.';
pub const SHALLOW_WATER_GLYPH: char = '~';
pub const DEEP_WATER_GLYPH: char = '≈';
pub const BARS_GLYPH: char = '#';
// FOREST THEME
pub const FOREST_WALL_GLYPH: char = '♣';

View file

@ -1,2 +0,0 @@
use std::error::Error;
use super::Config;

View file

@ -1,10 +1,3 @@
pub mod entity;
pub mod visuals;
pub mod glyphs;
pub mod messages;
pub mod char_create;
mod load;
use rltk::prelude::*; use rltk::prelude::*;
use toml::Value; use toml::Value;
use serde::{ Serialize, Deserialize }; use serde::{ Serialize, Deserialize };

View file

@ -14,6 +14,7 @@ use super::{
}; };
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
use crate::data::events;
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();
@ -80,7 +81,7 @@ pub fn delete_the_dead(ecs: &mut World) {
} }
// For everything that died, increment the event log, and delete. // For everything that died, increment the event log, and delete.
for victim in dead { for victim in dead {
gamelog::record_event("death_count", 1); gamelog::record_event(events::EVENT::TURN(1));
ecs.delete_entity(victim).expect("Unable to delete."); ecs.delete_entity(victim).expect("Unable to delete.");
} }
} }

26
src/data/events.rs Normal file
View file

@ -0,0 +1,26 @@
use serde::{ Deserialize, Serialize };
#[derive(Serialize, Deserialize, Clone)]
pub enum EVENT {
TURN(i32),
LEVEL(i32),
CHANGED_FLOOR(i32),
PLAYER_CONFUSED(i32),
KICKED_SOMETHING(i32),
BROKE_DOOR(i32),
LOOKED_FOR_HELP(i32),
KILLED(String),
DISCOVERED(String),
IDENTIFIED(String),
}
impl EVENT {
pub const COUNT_TURN: &str = "turns";
pub const COUNT_DEATH: &str = "deaths";
pub const COUNT_LEVEL: &str = "level";
pub const COUNT_CHANGED_FLOOR: &str = "changed_floor";
pub const COUNT_BROKE_DOOR: &str = "broke_door";
pub const COUNT_PLAYER_CONFUSED: &str = "player_confused";
pub const COUNT_KICK: &str = "kick";
pub const COUNT_LOOKED_FOR_HELP: &str = "looked_for_help";
}

5
src/data/mod.rs Normal file
View file

@ -0,0 +1,5 @@
pub mod entity;
pub mod visuals;
pub mod messages;
pub mod char_create;
pub mod events;

View file

@ -37,3 +37,25 @@ pub const DEEP_WATER_COLOUR: (u8, u8, u8) = (18, 33, 63);
pub const BARS_COLOUR: (u8, u8, u8) = (100, 100, 100); pub const BARS_COLOUR: (u8, u8, u8) = (100, 100, 100);
// FOREST THEME // FOREST THEME
pub const FOREST_WALL_COLOUR: (u8, u8, u8) = (0, 153, 0); pub const FOREST_WALL_COLOUR: (u8, u8, u8) = (0, 153, 0);
// DEFAULT THEME
#[allow(dead_code)]
pub const WALL_GLYPH: char = '#';
pub const FLOOR_GLYPH: char = '.';
pub const DOWN_STAIR_GLYPH: char = '>';
pub const UP_STAIR_GLYPH: char = '<';
pub const WOOD_FLOOR_GLYPH: char = '.';
pub const FENCE_GLYPH: char = '=';
pub const BRIDGE_GLYPH: char = '.';
pub const GRAVEL_GLYPH: char = ';';
pub const ROAD_GLYPH: char = '.';
pub const GRASS_GLYPH: char = '"';
pub const FOLIAGE_GLYPH: char = ':';
pub const HEAVY_FOLIAGE_GLYPH: char = ';';
pub const SAND_GLYPH: char = '.';
pub const SHALLOW_WATER_GLYPH: char = '~';
pub const DEEP_WATER_GLYPH: char = '≈';
pub const BARS_GLYPH: char = '#';
// FOREST THEME
pub const FOREST_WALL_GLYPH: char = '♣';

View file

@ -10,8 +10,9 @@ use crate::{
Player, Player,
Pools, Pools,
}; };
use crate::config::visuals::{ DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME }; use crate::data::visuals::{ DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME };
use crate::config::messages::LEVELUP_PLAYER; use crate::data::messages::LEVELUP_PLAYER;
use crate::data::events::*;
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
@ -161,7 +162,7 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
source_pools.level += 1; source_pools.level += 1;
// If it was the PLAYER that levelled up: // If it was the PLAYER that levelled up:
if ecs.read_storage::<Player>().get(source).is_some() { if ecs.read_storage::<Player>().get(source).is_some() {
gamelog::record_event("player_level", 1); gamelog::record_event(EVENT::LEVEL(1));
gamelog::Logger::new().append(LEVELUP_PLAYER).append_n(source_pools.level).append("!").log(); gamelog::Logger::new().append(LEVELUP_PLAYER).append_n(source_pools.level).append("!").log();
let player_pos = ecs.fetch::<Point>(); let player_pos = ecs.fetch::<Point>();
let map = ecs.fetch_mut::<Map>(); let map = ecs.fetch_mut::<Map>();

View file

@ -33,7 +33,7 @@ use crate::{
KnownSpell, KnownSpell,
KnownSpells, KnownSpells,
}; };
use crate::config::messages::*; use crate::data::messages::*;
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
pub fn item_trigger(source: Option<Entity>, item: Entity, target: &Targets, ecs: &mut World) { pub fn item_trigger(source: Option<Entity>, item: Entity, target: &Targets, ecs: &mut World) {

View file

@ -1,18 +1,48 @@
use std::collections::HashMap; use std::collections::{ HashSet, HashMap };
use std::sync::Mutex; use std::sync::Mutex;
use crate::data::events::EVENT;
lazy_static! { lazy_static! {
static ref EVENTS: Mutex<HashMap<String, i32>> = Mutex::new(HashMap::new()); /// A count of each event that has happened over the run. i.e. "turns", "descended", "ascended"
static ref EVENT_COUNTER: Mutex<HashMap<String, i32>> = Mutex::new(HashMap::new());
// A record of events that happened on a given turn. i.e. "Advanced to level 2".
pub static ref EVENTS: Mutex<HashMap<u32, Vec<String>>> = Mutex::new(HashMap::new());
static ref VISITED: Mutex<HashSet<i32>> = Mutex::new(HashSet::new());
} }
/// Makes a copy of event counts (FOR SERIALIZATION)
pub fn clone_event_counts() -> HashMap<String, i32> {
EVENT_COUNTER.lock().unwrap().clone()
}
/// Makes a copy of events (FOR SERIALIZATION)
pub fn clone_events() -> HashMap<u32, Vec<String>> {
EVENTS.lock().unwrap().clone()
}
/// Fetches event counter into mutex (FOR DESERIALIZATION)
pub fn restore_event_counter(events: HashMap<String, i32>) {
EVENT_COUNTER.lock().unwrap().clear();
events.iter().for_each(|(k, v)| {
EVENT_COUNTER.lock().unwrap().insert(k.to_string(), *v);
});
}
/// Fetches events into mutex (FOR DESERIALIZATION)
pub fn restore_events(events: HashMap<u32, Vec<String>>) {
EVENTS.lock().unwrap().clear();
events.iter().for_each(|(k, v)| {
EVENTS.lock().unwrap().insert(*k, v.to_vec());
});
}
/// Wipes all events - for starting a new game.
pub fn clear_events() { pub fn clear_events() {
EVENT_COUNTER.lock().unwrap().clear();
EVENTS.lock().unwrap().clear(); EVENTS.lock().unwrap().clear();
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn record_event<T: ToString>(event: T, n: i32) { /// Increments the event counter by n for a given event.
fn modify_event_count<T: ToString>(event: T, n: i32) {
let event_name = event.to_string(); let event_name = event.to_string();
let mut events_lock = EVENTS.lock(); let mut events_lock = EVENT_COUNTER.lock();
let mut events = events_lock.as_mut().unwrap(); let mut events = events_lock.as_mut().unwrap();
if let Some(e) = events.get_mut(&event_name) { if let Some(e) = events.get_mut(&event_name) {
*e += n; *e += n;
@ -20,10 +50,10 @@ pub fn record_event<T: ToString>(event: T, n: i32) {
events.insert(event_name, n); events.insert(event_name, n);
} }
} }
/// Returns how many times an event has taken place.
pub fn get_event_count<T: ToString>(event: T) -> i32 { pub fn get_event_count<T: ToString>(event: T) -> i32 {
let event_name = event.to_string(); let event_name = event.to_string();
let events_lock = EVENTS.lock(); let events_lock = EVENT_COUNTER.lock();
let events = events_lock.unwrap(); let events = events_lock.unwrap();
if let Some(e) = events.get(&event_name) { if let Some(e) = events.get(&event_name) {
*e *e
@ -31,14 +61,61 @@ pub fn get_event_count<T: ToString>(event: T) -> i32 {
0 0
} }
} }
/// Records an event on the current turn.
pub fn record_event(event: EVENT) {
let mut new_event: String = "unknown event".to_string();
let mut significant_event = true;
match event {
EVENT::TURN(n) => {
modify_event_count(EVENT::COUNT_TURN, n);
significant_event = false;
}
EVENT::LEVEL(n) => {
modify_event_count(EVENT::COUNT_LEVEL, n);
new_event = format!("Advanced to level {}", n);
}
EVENT::CHANGED_FLOOR(n) => {
modify_event_count(EVENT::COUNT_CHANGED_FLOOR, 1);
if VISITED.lock().unwrap().contains(&n) {
significant_event = false;
} else {
VISITED.lock().unwrap().insert(n);
new_event = format!("Visited level {} for the first time", n);
}
}
EVENT::KICKED_SOMETHING(n) => {
modify_event_count(EVENT::COUNT_KICK, n);
significant_event = false;
}
EVENT::BROKE_DOOR(n) => {
modify_event_count(EVENT::COUNT_BROKE_DOOR, n);
significant_event = false;
}
EVENT::PLAYER_CONFUSED(n) => {
modify_event_count(EVENT::COUNT_PLAYER_CONFUSED, n);
significant_event = false;
}
EVENT::LOOKED_FOR_HELP(n) => {
modify_event_count(EVENT::COUNT_LOOKED_FOR_HELP, n);
significant_event = false;
}
EVENT::KILLED(name) => {
new_event = format!("Killed {}", name);
}
EVENT::DISCOVERED(name) => {
new_event = format!("Discovered {}", name);
}
EVENT::IDENTIFIED(name) => {
new_event = format!("Identified {}", name);
}
}
pub fn clone_events() -> HashMap<String, i32> { if significant_event {
EVENTS.lock().unwrap().clone() EVENTS.lock()
} .as_mut()
.unwrap()
pub fn load_events(events: HashMap<String, i32>) { .entry(get_event_count(EVENT::COUNT_TURN) as u32)
EVENTS.lock().unwrap().clear(); .or_insert_with(Vec::new)
events.iter().for_each(|(k, v)| { .push(new_event);
EVENTS.lock().unwrap().insert(k.to_string(), *v); }
});
} }

View file

@ -1,5 +1,3 @@
use rltk::prelude::*;
mod builder; mod builder;
pub use builder::*; pub use builder::*;
mod logstore; mod logstore;
@ -9,6 +7,7 @@ mod events;
pub use events::*; pub use events::*;
use serde::{ Deserialize, Serialize }; use serde::{ Deserialize, Serialize };
use rltk::prelude::*;
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct LogFragment { pub struct LogFragment {
pub colour: RGB, pub colour: RGB,

View file

@ -1,7 +1,7 @@
use super::{ Skill, Skills }; use super::{ Skill, Skills };
use crate::gui::{ Ancestry, Class }; use crate::gui::{ Ancestry, Class };
use crate::config::entity; use crate::data::entity;
use crate::config::char_create::*; use crate::data::char_create::*;
use rltk::prelude::*; use rltk::prelude::*;
use std::cmp::max; use std::cmp::max;

View file

@ -1,6 +1,6 @@
use super::{ gamesystem::attr_bonus, gamesystem::get_attribute_rolls, Attributes, Pools, Renderable, RunState, State }; use super::{ gamesystem::attr_bonus, gamesystem::get_attribute_rolls, Attributes, Pools, Renderable, RunState, State };
use crate::config::entity; use crate::data::entity;
use crate::config::char_create::*; use crate::data::char_create::*;
use crate::{ use crate::{
raws, raws,
Attribute, Attribute,

View file

@ -33,7 +33,7 @@ use super::{
Viewshed, Viewshed,
BUC, BUC,
}; };
use crate::config::entity::CARRY_CAPACITY_PER_STRENGTH; use crate::data::entity::CARRY_CAPACITY_PER_STRENGTH;
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -47,6 +47,7 @@ mod identify_menu;
pub use identify_menu::*; pub use identify_menu::*;
mod tooltip; mod tooltip;
pub use cheat_menu::*; pub use cheat_menu::*;
use crate::data::events::*;
/// Gives a popup box with a message and a title, and waits for a keypress. /// Gives a popup box with a message and a title, and waits for a keypress.
#[allow(unused)] #[allow(unused)]
@ -329,7 +330,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
54, 54,
RGB::named(rltk::YELLOW), RGB::named(rltk::YELLOW),
RGB::named(rltk::BLACK), RGB::named(rltk::BLACK),
&format!("T{}", crate::gamelog::get_event_count("turns")) &format!("T{}", crate::gamelog::get_event_count(EVENT::COUNT_TURN))
); );
// Boxes and tooltips last, so they draw over everything else. // Boxes and tooltips last, so they draw over everything else.
@ -1135,22 +1136,22 @@ pub fn game_over(ctx: &mut Rltk) -> YesNoResult {
y, y,
RGB::named(rltk::GREEN), RGB::named(rltk::GREEN),
RGB::named(rltk::BLACK), RGB::named(rltk::BLACK),
format!("You survived for {} turns.", crate::gamelog::get_event_count("turns")) format!("You survived for {} turns.", crate::gamelog::get_event_count(EVENT::COUNT_TURN))
); );
y += 2; y += 2;
ctx.print_color(x, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), format!("And in the process, you")); ctx.print_color(x, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), format!("And in the process, you"));
y += 1; y += 1;
if crate::gamelog::get_event_count("descended") > 0 { if crate::gamelog::get_event_count(EVENT::COUNT_CHANGED_FLOOR) > 0 {
ctx.print_color( ctx.print_color(
x + 1, x + 1,
y, y,
RGB::named(rltk::WHITE), RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK), RGB::named(rltk::BLACK),
format!("- descended {} floor(s)", crate::gamelog::get_event_count("descended")) format!("- changed floor {} times", crate::gamelog::get_event_count(EVENT::COUNT_CHANGED_FLOOR))
); );
y += 1; y += 1;
} }
if crate::gamelog::get_event_count("kick_count") > 0 { if crate::gamelog::get_event_count(EVENT::COUNT_KICK) > 0 {
ctx.print_color( ctx.print_color(
x + 1, x + 1,
y, y,
@ -1158,29 +1159,29 @@ pub fn game_over(ctx: &mut Rltk) -> YesNoResult {
RGB::named(rltk::BLACK), RGB::named(rltk::BLACK),
format!( format!(
"- kicked {} time(s), breaking {} object(s)", "- kicked {} time(s), breaking {} object(s)",
crate::gamelog::get_event_count("kick_count"), crate::gamelog::get_event_count(EVENT::COUNT_KICK),
crate::gamelog::get_event_count("broken_doors") crate::gamelog::get_event_count(EVENT::COUNT_BROKE_DOOR)
) )
); );
y += 1; y += 1;
} }
if crate::gamelog::get_event_count("death_count") > 0 { if crate::gamelog::get_event_count(EVENT::COUNT_DEATH) > 0 {
ctx.print_color( ctx.print_color(
x + 1, x + 1,
y, y,
RGB::named(rltk::WHITE), RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK), RGB::named(rltk::BLACK),
format!("- slew {} other creature(s)", crate::gamelog::get_event_count("death_count")) format!("- slew {} other creature(s)", crate::gamelog::get_event_count(EVENT::COUNT_DEATH))
); );
y += 1; y += 1;
} }
if crate::gamelog::get_event_count("looked_for_help") > 0 { if crate::gamelog::get_event_count(EVENT::COUNT_LOOKED_FOR_HELP) > 0 {
ctx.print_color( ctx.print_color(
x + 1, x + 1,
y, y,
RGB::named(rltk::WHITE), RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK), RGB::named(rltk::BLACK),
format!("- forgot the controls {} time(s)", crate::gamelog::get_event_count("looked_for_help")) format!("- forgot the controls {} time(s)", crate::gamelog::get_event_count(EVENT::COUNT_LOOKED_FOR_HELP))
); );
} }

View file

@ -13,7 +13,7 @@ use crate::{
WantsToPickupItem, WantsToPickupItem,
}; };
use specs::prelude::*; use specs::prelude::*;
use crate::config::messages; use crate::data::messages;
pub struct ItemCollectionSystem {} pub struct ItemCollectionSystem {}

View file

@ -13,7 +13,7 @@ use crate::{
WantsToDropItem, WantsToDropItem,
}; };
use specs::prelude::*; use specs::prelude::*;
use crate::config::messages; use crate::data::messages;
pub struct ItemDropSystem {} pub struct ItemDropSystem {}

View file

@ -16,7 +16,7 @@ use crate::{
BUC, BUC,
}; };
use specs::prelude::*; use specs::prelude::*;
use crate::config::messages; use crate::data::messages;
pub struct ItemEquipSystem {} pub struct ItemEquipSystem {}

View file

@ -1,5 +1,7 @@
use crate::{ Beatitude, IdentifiedBeatitude, IdentifiedItem, Item, MasterDungeonMap, Name, ObfuscatedName, Player }; use crate::{ Beatitude, IdentifiedBeatitude, IdentifiedItem, Item, MasterDungeonMap, Name, ObfuscatedName, Player };
use specs::prelude::*; use specs::prelude::*;
use crate::data::events::*;
use crate::gamelog;
pub struct ItemIdentificationSystem {} pub struct ItemIdentificationSystem {}
@ -32,6 +34,9 @@ impl<'a> System<'a> for ItemIdentificationSystem {
for (_p, id) in (&player, &identified).join() { for (_p, id) in (&player, &identified).join() {
let tag = crate::raws::get_id_from_name(id.name.clone()); let tag = crate::raws::get_id_from_name(id.name.clone());
if !dm.identified_items.contains(&id.name) && crate::raws::is_tag_magic(&tag) { if !dm.identified_items.contains(&id.name) && crate::raws::is_tag_magic(&tag) {
if gamelog::get_event_count(EVENT::COUNT_TURN) != 1 {
gamelog::record_event(EVENT::IDENTIFIED(id.name.clone()));
}
dm.identified_items.insert(id.name.clone()); dm.identified_items.insert(id.name.clone());
for (entity, _item, name) in (&entities, &items, &names).join() { for (entity, _item, name) in (&entities, &items, &names).join() {
if name.name == id.name { if name.name == id.name {

View file

@ -13,7 +13,7 @@ use crate::{
}; };
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
use crate::config::messages; use crate::data::messages;
pub struct ItemRemoveSystem {} pub struct ItemRemoveSystem {}

View file

@ -29,6 +29,7 @@ mod inventory;
mod particle_system; mod particle_system;
use particle_system::ParticleBuilder; use particle_system::ParticleBuilder;
mod ai; mod ai;
mod data;
mod config; mod config;
mod effects; mod effects;
mod gamesystem; mod gamesystem;
@ -36,6 +37,7 @@ mod random_table;
mod rex_assets; mod rex_assets;
mod spatial; mod spatial;
mod morgue; mod morgue;
use data::events::*;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
@ -177,13 +179,11 @@ impl State {
current_id = worldmap_resource.id; current_id = worldmap_resource.id;
} }
// Record the correct type of event // Record the correct type of event
if offset > 0 { if offset < 0 && current_id == 1 {
gamelog::record_event("descended", 1);
} else if current_id == 1 {
gamelog::Logger::new().append("CHEAT MENU: YOU CAN'T DO THAT.").colour((255, 0, 0)).log(); gamelog::Logger::new().append("CHEAT MENU: YOU CAN'T DO THAT.").colour((255, 0, 0)).log();
return; return;
} else { } else {
gamelog::record_event("ascended", 1); gamelog::record_event(EVENT::CHANGED_FLOOR(current_id + offset));
} }
// Freeze the current level // Freeze the current level
map::dungeon::freeze_entities(&mut self.ecs); map::dungeon::freeze_entities(&mut self.ecs);
@ -213,7 +213,7 @@ impl State {
self.generate_world_map(1, 0); self.generate_world_map(1, 0);
gamelog::setup_log(); gamelog::setup_log();
gamelog::record_event("player_level", 1); gamelog::record_event(EVENT::LEVEL(1));
} }
} }
@ -537,7 +537,7 @@ impl GameState for State {
let result = gui::show_help(ctx); let result = gui::show_help(ctx);
match result { match result {
gui::YesNoResult::Yes => { gui::YesNoResult::Yes => {
gamelog::record_event("looked_for_help", 1); gamelog::record_event(EVENT::LOOKED_FOR_HELP(1));
new_runstate = RunState::AwaitingInput; new_runstate = RunState::AwaitingInput;
} }
_ => {} _ => {}
@ -628,7 +628,7 @@ fn main() -> rltk::BError {
.with_simple_console(DISPLAYWIDTH, DISPLAYHEIGHT, "curses14x16.png") .with_simple_console(DISPLAYWIDTH, DISPLAYHEIGHT, "curses14x16.png")
.build()?; .build()?;
if config::CONFIG.visuals.with_scanlines { if config::CONFIG.visuals.with_scanlines {
context.with_post_scanlines(config::visuals::WITH_SCREEN_BURN); context.with_post_scanlines(data::visuals::WITH_SCREEN_BURN);
} }
let mut gs = State { let mut gs = State {
@ -733,7 +733,7 @@ fn main() -> rltk::BError {
gs.ecs.insert(rex_assets::RexAssets::new()); gs.ecs.insert(rex_assets::RexAssets::new());
gamelog::setup_log(); gamelog::setup_log();
gamelog::record_event("player_level", 1); gamelog::record_event(EVENT::LEVEL(1));
gs.generate_world_map(1, 0); gs.generate_world_map(1, 0);
rltk::main_loop(context, gs) rltk::main_loop(context, gs)

View file

@ -4,6 +4,7 @@ use rltk::prelude::*;
use serde::{ Deserialize, Serialize }; use serde::{ Deserialize, Serialize };
use specs::prelude::*; use specs::prelude::*;
use std::collections::{ HashMap, HashSet }; use std::collections::{ HashMap, HashSet };
use crate::data::events::*;
#[derive(Default, Serialize, Deserialize, Clone)] #[derive(Default, Serialize, Deserialize, Clone)]
pub struct MasterDungeonMap { pub struct MasterDungeonMap {
@ -241,7 +242,7 @@ fn transition_to_new_map(ecs: &mut World, new_id: i32) -> Vec<Map> {
// Might need this to fallback to 1, but if player // Might need this to fallback to 1, but if player
// level isn't found at all, there's a bigger concern // level isn't found at all, there's a bigger concern
// concern than just this function not working. // concern than just this function not working.
let player_level = gamelog::get_event_count("player_level"); let player_level = gamelog::get_event_count(EVENT::COUNT_LEVEL);
let mut builder = map_builders::level_builder(new_id, &mut rng, 100, 50, player_level); let mut builder = map_builders::level_builder(new_id, &mut rng, 100, 50, player_level);
builder.build_map(&mut rng); builder.build_map(&mut rng);
std::mem::drop(rng); std::mem::drop(rng);

View file

@ -1,5 +1,6 @@
use crate::{ config::CONFIG, gamelog, raws, spawner, Clock, Map, RandomNumberGenerator, TakingTurn }; use crate::{ config::CONFIG, gamelog, raws, spawner, Clock, Map, RandomNumberGenerator, TakingTurn };
use specs::prelude::*; use specs::prelude::*;
use crate::data::events::*;
const TRY_SPAWN_CHANCE: i32 = 70; const TRY_SPAWN_CHANCE: i32 = 70;
@ -32,7 +33,7 @@ pub fn try_spawn_interval(ecs: &mut World) {
fn spawn_random_mob_in_free_nonvisible_tile(ecs: &mut World) { fn spawn_random_mob_in_free_nonvisible_tile(ecs: &mut World) {
let map = ecs.fetch::<Map>(); let map = ecs.fetch::<Map>();
let mut available_tiles = populate_unblocked_nonvisible(&map); let mut available_tiles = populate_unblocked_nonvisible(&map);
let player_level = gamelog::get_event_count("player_level"); let player_level = gamelog::get_event_count(EVENT::COUNT_LEVEL);
rltk::console::log(player_level); rltk::console::log(player_level);
let difficulty = (map.difficulty + player_level) / 2; let difficulty = (map.difficulty + player_level) / 2;
if available_tiles.len() == 0 { if available_tiles.len() == 0 {

View file

@ -8,7 +8,7 @@ pub use interval_spawning_system::try_spawn_interval;
pub mod dungeon; pub mod dungeon;
pub use dungeon::{ level_transition, MasterDungeonMap }; pub use dungeon::{ level_transition, MasterDungeonMap };
pub mod themes; pub mod themes;
use crate::config::visuals::MAX_COLOUR_OFFSET_PERCENT; use crate::data::visuals::MAX_COLOUR_OFFSET_PERCENT;
// FIXME: If the map size gets too small, entities stop being rendered starting from the right. // FIXME: If the map size gets too small, entities stop being rendered starting from the right.
// i.e. on a map size of 40*40, only entities to the left of the player are rendered. // i.e. on a map size of 40*40, only entities to the left of the player are rendered.

View file

@ -1,6 +1,5 @@
use super::{ Map, Point, TileType }; use super::{ Map, Point, TileType };
use crate::config::glyphs::*; use crate::data::visuals::*;
use crate::config::visuals::*;
use crate::config::CONFIG; use crate::config::CONFIG;
use rltk::prelude::*; use rltk::prelude::*;
use std::ops::{ Add, Mul }; use std::ops::{ Add, Mul };
@ -269,7 +268,7 @@ fn darken_by_distance(pos: Point, other_pos: Point) -> f32 {
let distance = DistanceAlg::Pythagoras.distance2d(pos, other_pos) as f32; // Get distance in tiles. let distance = DistanceAlg::Pythagoras.distance2d(pos, other_pos) as f32; // Get distance in tiles.
let interp_factor = let interp_factor =
(distance - START_DARKEN_AT_N_TILES) / (distance - START_DARKEN_AT_N_TILES) /
((crate::config::entity::DEFAULT_VIEWSHED_STANDARD as f32) - START_DARKEN_AT_N_TILES); ((crate::data::entity::DEFAULT_VIEWSHED_STANDARD as f32) - START_DARKEN_AT_N_TILES);
let interp_factor = interp_factor.max(0.0).min(1.0); // Clamp [0-1] let interp_factor = interp_factor.max(0.0).min(1.0); // Clamp [0-1]
return ( return (
1.0 - 1.0 -

View file

@ -9,6 +9,7 @@ use specs::prelude::*;
use rltk::prelude::*; use rltk::prelude::*;
use rltk::to_char; use rltk::to_char;
use std::collections::HashMap; use std::collections::HashMap;
use crate::data::events::*;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
pub fn create_morgue_file(ecs: &World) { pub fn create_morgue_file(ecs: &World) {
@ -25,7 +26,7 @@ pub fn create_morgue_file(ecs: &World) {
} }
let morgue_info = create_morgue_string(ecs); let morgue_info = create_morgue_string(ecs);
let file_name = create_file_name(ecs, morgue_dir); let file_name = create_file_name(ecs, morgue_dir);
if let Err(err) = write_morgue_file(morgue_info.as_str(), file_name.as_str()) { if let Err(err) = write_morgue_file(file_name.as_str(), morgue_info.as_str()) {
console::log(format!("Unable to write the morgue file: {}", err)); console::log(format!("Unable to write the morgue file: {}", err));
}; };
} }
@ -75,10 +76,13 @@ fn create_morgue_string(ecs: &World) -> String {
morgue_info.push_str(&create_boxed_text(header.as_str(), None)); morgue_info.push_str(&create_boxed_text(header.as_str(), None));
morgue_info.push_str(&draw_tombstone(ecs, header.len())); morgue_info.push_str(&draw_tombstone(ecs, header.len()));
morgue_info.push_str(&draw_map(ecs)); morgue_info.push_str(&draw_map(ecs));
morgue_info.push_str("\n");
morgue_info.push_str(&create_boxed_text("Equipment", None)); morgue_info.push_str(&create_boxed_text("Equipment", None));
morgue_info.push_str(&draw_equipment(ecs)); morgue_info.push_str(&draw_equipment(ecs));
morgue_info.push_str(&create_boxed_text("Backpack", None)); morgue_info.push_str(&create_boxed_text("Backpack", None));
morgue_info.push_str(&draw_backpack(ecs)); morgue_info.push_str(&draw_backpack(ecs));
morgue_info.push_str(&create_boxed_text("Significant Events", None));
morgue_info.push_str(&draw_events_list());
return morgue_info; return morgue_info;
} }
@ -133,7 +137,7 @@ fn draw_tombstone(ecs: &World, len: usize) -> String {
"", "",
map.name, map.name,
map.id, map.id,
gamelog::get_event_count("turns"), gamelog::get_event_count(EVENT::COUNT_TURN),
"", "",
"", "",
p = pad p = pad
@ -229,3 +233,28 @@ fn draw_backpack(ecs: &World) -> String {
result.push_str("\n"); result.push_str("\n");
return result; return result;
} }
fn draw_events_list() -> String {
// Initialise default (empty) string
let mut result: String = Default::default();
// Get lock on events mutex
let lock = gamelog::EVENTS.lock().unwrap();
// Collect all keys, and sort in ascending value (by turn count)
let mut sorted_keys: Vec<u32> = lock
.keys()
.map(|k| *k)
.collect();
sorted_keys.sort();
// Iterate through sorted keys, looking for corresponding values, and append on newline
for key in sorted_keys {
if let Some(value) = lock.get(&key) {
result.push_str(&format!("{:<4} | ", key));
for event in value.iter() {
result.push_str(&format!("{}", event));
}
result.push_str("\n");
}
}
return result;
}

View file

@ -1,7 +1,7 @@
use super::{ ParticleLifetime, Position, Renderable, Rltk }; use super::{ ParticleLifetime, Position, Renderable, Rltk };
use rltk::RGB; use rltk::RGB;
use specs::prelude::*; use specs::prelude::*;
use crate::config::visuals::{ DEFAULT_PARTICLE_LIFETIME, SHORT_PARTICLE_LIFETIME }; use crate::data::visuals::{ DEFAULT_PARTICLE_LIFETIME, SHORT_PARTICLE_LIFETIME };
/// Runs each tick, deleting particles who are past their expiry. /// Runs each tick, deleting particles who are past their expiry.
// Should make an addition to this to also spawn delayed particles, // Should make an addition to this to also spawn delayed particles,

View file

@ -34,6 +34,7 @@ use rltk::prelude::*;
use rltk::{ Point, RandomNumberGenerator, Rltk, VirtualKeyCode }; use rltk::{ Point, RandomNumberGenerator, Rltk, VirtualKeyCode };
use specs::prelude::*; use specs::prelude::*;
use std::cmp::{ max, min }; use std::cmp::{ max, min };
use crate::data::events::*;
pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState { pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState {
let mut positions = ecs.write_storage::<Position>(); let mut positions = ecs.write_storage::<Position>();
@ -263,7 +264,7 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState {
.log(); .log();
something_was_destroyed = Some(potential_target); something_was_destroyed = Some(potential_target);
destroyed_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y)); destroyed_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y));
gamelog::record_event("broken_doors", 1); gamelog::record_event(EVENT::BROKE_DOOR(1));
return false; return false;
// 66% chance of just kicking it. // 66% chance of just kicking it.
} else { } else {
@ -308,7 +309,7 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState {
ecs.delete_entity(destroyed_thing).expect("Unable to delete."); ecs.delete_entity(destroyed_thing).expect("Unable to delete.");
} }
gamelog::record_event("kick_count", 1); gamelog::record_event(EVENT::KICKED_SOMETHING(1));
return RunState::Ticking; return RunState::Ticking;
} }

View file

@ -38,6 +38,7 @@ pub fn save_game(ecs: &mut World) {
.with(DMSerializationHelper { .with(DMSerializationHelper {
map: dungeon_master, map: dungeon_master,
log: crate::gamelog::clone_log(), log: crate::gamelog::clone_log(),
event_counts: crate::gamelog::clone_event_counts(),
events: crate::gamelog::clone_events(), events: crate::gamelog::clone_events(),
}) })
.marked::<SimpleMarker<SerializeMe>>() .marked::<SimpleMarker<SerializeMe>>()
@ -280,7 +281,8 @@ pub fn load_game(ecs: &mut World) {
*dungeonmaster = h.map.clone(); *dungeonmaster = h.map.clone();
deleteme2 = Some(e); deleteme2 = Some(e);
crate::gamelog::restore_log(&mut h.log.clone()); crate::gamelog::restore_log(&mut h.log.clone());
crate::gamelog::load_events(h.events.clone()); crate::gamelog::restore_event_counter(h.event_counts.clone());
crate::gamelog::restore_events(h.events.clone());
} }
for (e, _p, pos) in (&entities, &player, &position).join() { for (e, _p, pos) in (&entities, &player, &position).join() {
let mut ppos = ecs.write_resource::<rltk::Point>(); let mut ppos = ecs.write_resource::<rltk::Point>();

View file

@ -24,7 +24,7 @@ use super::{
TileType, TileType,
Viewshed, Viewshed,
}; };
use crate::config::entity; use crate::data::entity;
use crate::gamesystem::*; use crate::gamesystem::*;
use rltk::{ RandomNumberGenerator, RGB }; use rltk::{ RandomNumberGenerator, RGB };
use specs::prelude::*; use specs::prelude::*;