cleanup and bugfixes, standardising log colours

This commit is contained in:
Llywelwyn 2023-08-17 04:44:40 +01:00
parent dd4e0aaee4
commit ff1afed92c
10 changed files with 153 additions and 73 deletions

View file

@ -34,7 +34,7 @@
"name": { "name": "scroll of fireball", "plural": "scrolls of fireball" }, "name": { "name": "scroll of fireball", "plural": "scrolls of fireball" },
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, "renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 0.5, "weight": 0.5,
"value": 150, "value": 200,
"flags": ["CONSUMABLE", "DESTRUCTIBLE"], "flags": ["CONSUMABLE", "DESTRUCTIBLE"],
"effects": { "ranged": "10", "damage": "8d6", "aoe": "3" }, "effects": { "ranged": "10", "damage": "8d6", "aoe": "3" },
"magic": { "class": "rare", "naming": "scroll" } "magic": { "class": "rare", "naming": "scroll" }
@ -44,7 +44,7 @@
"name": { "name": "cursed scroll of fireball", "plural": "cursed scrolls of fireball" }, "name": { "name": "cursed scroll of fireball", "plural": "cursed scrolls of fireball" },
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, "renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 0.5, "weight": 0.5,
"value": 150, "value": 200,
"flags": ["CONSUMABLE", "DESTRUCTIBLE", "CURSED"], "flags": ["CONSUMABLE", "DESTRUCTIBLE", "CURSED"],
"effects": { "ranged": "10", "damage": "8d6", "aoe": "3" }, "effects": { "ranged": "10", "damage": "8d6", "aoe": "3" },
"magic": { "class": "rare", "naming": "scroll" } "magic": { "class": "rare", "naming": "scroll" }
@ -59,6 +59,16 @@
"effects": { "ranged": "10", "confusion": "4" }, "effects": { "ranged": "10", "confusion": "4" },
"magic": { "class": "uncommon", "naming": "scroll" } "magic": { "class": "uncommon", "naming": "scroll" }
}, },
{
"id": "scroll_mass_confusion",
"name": { "name": "scroll of mass confusion", "plural": "scrolls of mass confusion" },
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 0.5,
"value": 200,
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
"effects": { "ranged": "10", "aoe": "4", "confusion": "3" },
"magic": { "class": "veryrare", "naming": "scroll" }
},
{ {
"id": "scroll_magicmap", "id": "scroll_magicmap",
"name": { "name": "scroll of magic mapping", "plural": "scrolls of magic mapping" }, "name": { "name": "scroll of magic mapping", "plural": "scrolls of magic mapping" },

View file

@ -1,4 +1,4 @@
use crate::{gamelog, Clock, Player, Pools, Position, RunState, TakingTurn}; use crate::{gamelog, Clock, Player, Pools, Position, TakingTurn};
use specs::prelude::*; use specs::prelude::*;
pub struct RegenSystem {} pub struct RegenSystem {}
@ -11,7 +11,6 @@ impl<'a> System<'a> for RegenSystem {
type SystemData = ( type SystemData = (
ReadStorage<'a, Clock>, ReadStorage<'a, Clock>,
Entities<'a>, Entities<'a>,
ReadExpect<'a, RunState>,
ReadStorage<'a, Position>, ReadStorage<'a, Position>,
WriteStorage<'a, Pools>, WriteStorage<'a, Pools>,
ReadStorage<'a, TakingTurn>, ReadStorage<'a, TakingTurn>,
@ -19,12 +18,15 @@ impl<'a> System<'a> for RegenSystem {
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let (clock, entities, runstate, positions, mut pools, turns, player) = data; let (clock, entities, positions, mut pools, turns, player) = data;
if *runstate != RunState::Ticking { let mut clock_turn = false;
for (_e, _c, _t) in (&entities, &clock, &turns).join() {
clock_turn = true;
}
if !clock_turn {
return; return;
} }
for (_e, _c, _t) in (&entities, &clock, &turns).join() { let current_turn = gamelog::get_event_count("turns");
let current_turn = gamelog::get_event_count("turns") + 1;
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);
@ -37,7 +39,6 @@ impl<'a> System<'a> for RegenSystem {
} }
} }
} }
}
} }
fn get_player_hp_regen_turn(level: i32) -> i32 { fn get_player_hp_regen_turn(level: i32) -> i32 {

View file

@ -1,4 +1,9 @@
use crate::{gamelog, Confusion, Name, ParticleBuilder, Position, RunState, TakingTurn}; use crate::{
effects::{add_effect, EffectType, Targets},
gamelog,
gui::renderable_colour,
Clock, Confusion, Name, Renderable, TakingTurn,
};
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
@ -8,37 +13,93 @@ impl<'a> System<'a> for TurnStatusSystem {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
WriteStorage<'a, TakingTurn>, WriteStorage<'a, TakingTurn>,
ReadStorage<'a, Clock>,
WriteStorage<'a, Confusion>, WriteStorage<'a, Confusion>,
Entities<'a>, Entities<'a>,
ReadExpect<'a, RunState>,
ReadStorage<'a, Name>, ReadStorage<'a, Name>,
ReadStorage<'a, Position>, ReadExpect<'a, Entity>,
WriteExpect<'a, ParticleBuilder>, ReadStorage<'a, Renderable>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let (mut turns, mut confusion, entities, runstate, names, positions, mut particle_builder) = data; let (mut turns, clock, mut confusion, entities, names, player_entity, renderables) = data;
if *runstate != RunState::Ticking { let mut clock_tick = false;
for (_e, _c, _t) in (&entities, &clock, &turns).join() {
clock_tick = true;
}
if !clock_tick {
return; return;
} }
let mut remove_turn: Vec<Entity> = Vec::new(); let mut logger = gamelog::Logger::new();
let mut remove_confusion: Vec<Entity> = Vec::new(); let mut log = false;
for (entity, _turn, confused, name, pos) in (&entities, &mut turns, &mut confusion, &names, &positions).join() { let mut not_my_turn: Vec<Entity> = Vec::new();
let mut not_confused: Vec<Entity> = Vec::new();
for (entity, _turn, confused, name) in (&entities, &mut turns, &mut confusion, &names).join() {
log = true;
confused.turns -= 1; confused.turns -= 1;
if confused.turns < 1 { if confused.turns < 1 {
remove_confusion.push(entity); not_confused.push(entity);
gamelog::Logger::new().npc_name(&name.name).colour(WHITE).append("snaps out of it.").log(); if entity == *player_entity {
particle_builder.request(pos.x, pos.y, RGB::named(LIGHT_BLUE), RGB::named(BLACK), to_cp437('!'), 200.0); logger = logger
.colour(renderable_colour(&renderables, entity))
.append(&name.name)
.colour(WHITE)
.append("snap out of it.");
} else { } else {
remove_turn.push(entity); logger = logger
gamelog::Logger::new().npc_name(&name.name).colour(WHITE).append("is confused.").log(); .append("The")
particle_builder.request(pos.x, pos.y, RGB::named(MAGENTA), RGB::named(BLACK), to_cp437('?'), 200.0); .colour(renderable_colour(&renderables, entity))
.append(&name.name)
.colour(WHITE)
.append("snaps out of it.");
}
add_effect(
None,
EffectType::Particle {
glyph: to_cp437('!'),
fg: RGB::named(LIGHT_BLUE),
bg: RGB::named(BLACK),
lifespan: 200.0,
delay: 0.0,
},
Targets::Entity { target: entity },
);
} else {
not_my_turn.push(entity);
if entity == *player_entity {
logger = logger
.colour(renderable_colour(&renderables, entity))
.append(&name.name)
.colour(WHITE)
.append("are confused!");
} else {
logger = logger
.append("The")
.colour(renderable_colour(&renderables, entity))
.append(&name.name)
.colour(WHITE)
.append("is confused!");
}
add_effect(
None,
EffectType::Particle {
glyph: to_cp437('?'),
fg: RGB::named(MAGENTA),
bg: RGB::named(BLACK),
lifespan: 200.0,
delay: 0.0,
},
Targets::Entity { target: entity },
);
} }
} }
for e in remove_turn { if log {
logger.log();
}
for e in not_my_turn {
turns.remove(e); turns.remove(e);
} }
for e in remove_confusion { for e in not_confused {
confusion.remove(e); confusion.remove(e);
} }
} }

View file

@ -2,7 +2,7 @@ use super::{add_effect, targeting, EffectSpawner, EffectType, Entity, Targets, W
use crate::{ use crate::{
gamelog, gamelog,
gamesystem::{hp_per_level, mana_per_level}, gamesystem::{hp_per_level, mana_per_level},
Attributes, GrantsXP, Map, Player, Pools, DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME, Attributes, Confusion, GrantsXP, Map, Player, Pools, DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME,
}; };
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
@ -53,6 +53,14 @@ pub fn heal_damage(ecs: &mut World, heal: &EffectSpawner, target: Entity) {
} }
} }
pub fn add_confusion(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
if let EffectType::Confusion { turns } = &effect.effect_type {
ecs.write_storage::<Confusion>()
.insert(target, Confusion { turns: *turns })
.expect("Unable to insert Confusion");
}
}
pub fn bloodstain(ecs: &mut World, target: usize) { pub fn bloodstain(ecs: &mut World, target: usize) {
let mut map = ecs.fetch_mut::<Map>(); let mut map = ecs.fetch_mut::<Map>();
// If the current tile isn't bloody, bloody it. // If the current tile isn't bloody, bloody it.

View file

@ -20,6 +20,7 @@ lazy_static! {
pub enum EffectType { pub enum EffectType {
Damage { amount: i32 }, Damage { amount: i32 },
Healing { amount: i32 }, Healing { amount: i32 },
Confusion { turns: i32 },
Bloodstain, Bloodstain,
Particle { glyph: FontCharType, fg: RGB, bg: RGB, lifespan: f32, delay: f32 }, Particle { glyph: FontCharType, fg: RGB, bg: RGB, lifespan: f32, delay: f32 },
EntityDeath, EntityDeath,
@ -98,6 +99,7 @@ fn tile_effect_hits_entities(effect: &EffectType) -> bool {
EffectType::Damage { .. } => true, EffectType::Damage { .. } => true,
EffectType::Healing { .. } => true, EffectType::Healing { .. } => true,
EffectType::RestoreNutrition { .. } => true, EffectType::RestoreNutrition { .. } => true,
EffectType::Confusion { .. } => true,
_ => false, _ => false,
} }
} }
@ -107,6 +109,7 @@ fn affect_entity(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
match &effect.effect_type { match &effect.effect_type {
EffectType::Damage { .. } => damage::inflict_damage(ecs, effect, target), EffectType::Damage { .. } => damage::inflict_damage(ecs, effect, target),
EffectType::Healing { .. } => damage::heal_damage(ecs, effect, target), EffectType::Healing { .. } => damage::heal_damage(ecs, effect, target),
EffectType::Confusion { .. } => damage::add_confusion(ecs, effect, target),
EffectType::Bloodstain { .. } => { EffectType::Bloodstain { .. } => {
if let Some(pos) = targeting::entity_position(ecs, target) { if let Some(pos) = targeting::entity_position(ecs, target) {
damage::bloodstain(ecs, pos) damage::bloodstain(ecs, pos)

View file

@ -1,7 +1,7 @@
use super::{add_effect, spatial, EffectType, Entity, Targets, World}; use super::{add_effect, spatial, EffectType, Entity, Targets, World};
use crate::{ use crate::{
gamelog, gui::item_colour_ecs, gui::obfuscate_name_ecs, Consumable, Cursed, InflictsDamage, MagicMapper, Prop, gamelog, gui::item_colour_ecs, gui::obfuscate_name_ecs, Confusion, Consumable, Cursed, InflictsDamage, MagicMapper,
ProvidesHealing, ProvidesNutrition, RandomNumberGenerator, Renderable, RunState, Prop, ProvidesHealing, ProvidesNutrition, RandomNumberGenerator, Renderable, RunState,
}; };
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
@ -43,6 +43,8 @@ fn event_trigger(source: Option<Entity>, entity: Entity, target: &Targets, ecs:
logger = handle_healing(ecs, &mut event, logger); logger = handle_healing(ecs, &mut event, logger);
// DOES DAMAGE // DOES DAMAGE
logger = handle_damage(ecs, &mut event, logger); logger = handle_damage(ecs, &mut event, logger);
// APPLIES CONFUSION
logger = handle_confusion(ecs, &mut event, logger);
if event.log { if event.log {
logger.log(); logger.log();
} }
@ -83,7 +85,7 @@ fn handle_healing(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::L
let mut rng = ecs.write_resource::<RandomNumberGenerator>(); let mut rng = ecs.write_resource::<RandomNumberGenerator>();
let roll = rng.roll_dice(healing_item.n_dice, healing_item.sides) + healing_item.modifier; let roll = rng.roll_dice(healing_item.n_dice, healing_item.sides) + healing_item.modifier;
add_effect(event.source, EffectType::Healing { amount: roll }, event.target.clone()); add_effect(event.source, EffectType::Healing { amount: roll }, event.target.clone());
logger = logger.append("You recover some vigour."); logger = logger.append("You recover some vigour.").buc(event.buc, None, Some("You feel great!"));
event.log = true; event.log = true;
} }
return logger; return logger;
@ -115,8 +117,14 @@ fn handle_damage(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Lo
return logger; return logger;
} }
fn handle_confusion(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Logger) -> gamelog::Logger {
if let Some(confusion) = ecs.read_storage::<Confusion>().get(event.entity) {
add_effect(event.source, EffectType::Confusion { turns: confusion.turns }, event.target.clone());
}
return logger;
}
fn get_entity_targets(target: &Targets) -> Vec<Entity> { fn get_entity_targets(target: &Targets) -> Vec<Entity> {
rltk::console::log("ayo");
let mut entities: Vec<Entity> = Vec::new(); let mut entities: Vec<Entity> = Vec::new();
match target { match target {
Targets::Entity { target } => entities.push(*target), Targets::Entity { target } => entities.push(*target),

View file

@ -449,6 +449,15 @@ pub fn obfuscate_name_ecs(ecs: &World, item: Entity) -> (String, String) {
return (singular, plural); return (singular, plural);
} }
/// Gets renderable colour as tuple of u8
pub fn renderable_colour(renderables: &ReadStorage<Renderable>, entity: Entity) -> (u8, u8, u8) {
return if let Some(renderable) = renderables.get(entity) {
((renderable.fg.r * 255.0) as u8, (renderable.fg.g * 255.0) as u8, (renderable.fg.b * 255.0) as u8)
} else {
WHITE
};
}
pub fn item_colour_ecs(ecs: &World, item: Entity) -> (u8, u8, u8) { pub fn item_colour_ecs(ecs: &World, item: Entity) -> (u8, u8, u8) {
let dm = ecs.fetch::<MasterDungeonMap>(); let dm = ecs.fetch::<MasterDungeonMap>();
if let Some(name) = ecs.read_storage::<Name>().get(item) { if let Some(name) = ecs.read_storage::<Name>().get(item) {

View file

@ -1,4 +1,4 @@
use super::{camera::get_screen_bounds, Attributes, Hidden, Map, Pools, Position, Renderable, Rltk, World, RGB}; use super::{camera::get_screen_bounds, Attributes, Hidden, Map, Name, Pools, Position, Renderable, Rltk, World, RGB};
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
@ -43,6 +43,7 @@ impl Tooltip {
pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) { pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) = get_screen_bounds(ecs, ctx); let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) = get_screen_bounds(ecs, ctx);
let map = ecs.fetch::<Map>(); let map = ecs.fetch::<Map>();
let names = ecs.read_storage::<Name>();
let positions = ecs.read_storage::<Position>(); let positions = ecs.read_storage::<Position>();
let renderables = ecs.read_storage::<Renderable>(); let renderables = ecs.read_storage::<Renderable>();
let hidden = ecs.read_storage::<Hidden>(); let hidden = ecs.read_storage::<Hidden>();
@ -69,7 +70,7 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
} }
let mut tooltips: Vec<Tooltip> = Vec::new(); let mut tooltips: Vec<Tooltip> = Vec::new();
for (entity, position, renderable, _hidden) in (&entities, &positions, &renderables, !&hidden).join() { for (entity, position, renderable, _name, _hidden) in (&entities, &positions, &renderables, &names, !&hidden).join() {
if position.x == mouse_pos_adjusted.0 && position.y == mouse_pos_adjusted.1 { if position.x == mouse_pos_adjusted.0 && position.y == mouse_pos_adjusted.1 {
let mut tip = Tooltip::new(); let mut tip = Tooltip::new();
tip.add(crate::gui::obfuscate_name_ecs(ecs, entity).0, renderable.fg); tip.add(crate::gui::obfuscate_name_ecs(ecs, entity).0, renderable.fg);

View file

@ -90,11 +90,6 @@ impl State {
fn run_systems(&mut self) { fn run_systems(&mut self) {
let mut mapindex = spatial::MapIndexingSystem {}; let mut mapindex = spatial::MapIndexingSystem {};
let mut vis = VisibilitySystem {}; let mut vis = VisibilitySystem {};
let mut regen_system = ai::RegenSystem {};
let mut energy = ai::EnergySystem {};
let mut encumbrance_system = ai::EncumbranceSystem {};
let mut turn_status_system = ai::TurnStatusSystem {};
let mut quip_system = ai::QuipSystem {};
let mut trigger_system = trigger_system::TriggerSystem {}; let mut trigger_system = trigger_system::TriggerSystem {};
let mut melee_system = MeleeCombatSystem {}; let mut melee_system = MeleeCombatSystem {};
let mut damage_system = DamageSystem {}; let mut damage_system = DamageSystem {};
@ -109,11 +104,6 @@ impl State {
mapindex.run_now(&self.ecs); mapindex.run_now(&self.ecs);
vis.run_now(&self.ecs); vis.run_now(&self.ecs);
regen_system.run_now(&self.ecs);
encumbrance_system.run_now(&self.ecs);
energy.run_now(&self.ecs);
quip_system.run_now(&self.ecs);
turn_status_system.run_now(&self.ecs);
self.run_ai(); self.run_ai();
trigger_system.run_now(&self.ecs); trigger_system.run_now(&self.ecs);
inventory_system.run_now(&self.ecs); inventory_system.run_now(&self.ecs);
@ -132,12 +122,22 @@ impl State {
} }
fn run_ai(&mut self) { fn run_ai(&mut self) {
let mut adjacent_ai = ai::AdjacentAI {}; let mut encumbrance_system = ai::EncumbranceSystem {}; // Must run first, as it affects energy regen.
let mut energy = ai::EnergySystem {}; // Figures out who deserves a turn.
let mut regen_system = ai::RegenSystem {}; // Restores HP on appropriate clock ticks.
let mut turn_status_system = ai::TurnStatusSystem {}; // Ticks stasuses. Should anyone now lose their turn? i.e. confusion
let mut quip_system = ai::QuipSystem {}; // Quipping is "free". It doesn't use up a turn.
let mut adjacent_ai = ai::AdjacentAI {}; // AdjacentAI -> DefaultAI are all exclusive. If one acts, the entity's turn is over.
let mut visible_ai = ai::VisibleAI {}; let mut visible_ai = ai::VisibleAI {};
let mut approach_ai = ai::ApproachAI {}; let mut approach_ai = ai::ApproachAI {};
let mut flee_ai = ai::FleeAI {}; let mut flee_ai = ai::FleeAI {};
let mut chase_ai = ai::ChaseAI {}; let mut chase_ai = ai::ChaseAI {};
let mut default_move_ai = ai::DefaultAI {}; let mut default_move_ai = ai::DefaultAI {};
encumbrance_system.run_now(&self.ecs);
energy.run_now(&self.ecs);
regen_system.run_now(&self.ecs);
turn_status_system.run_now(&self.ecs);
quip_system.run_now(&self.ecs);
adjacent_ai.run_now(&self.ecs); adjacent_ai.run_now(&self.ecs);
visible_ai.run_now(&self.ecs); visible_ai.run_now(&self.ecs);
approach_ai.run_now(&self.ecs); approach_ai.run_now(&self.ecs);

View file

@ -91,27 +91,6 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
raws::SpawnType::Carried { by: player }, raws::SpawnType::Carried { by: player },
0, 0,
); );
raws::spawn_named_entity(
&raws::RAWS.lock().unwrap(),
ecs,
"scroll_confusion",
raws::SpawnType::Carried { by: player },
0,
);
raws::spawn_named_entity(
&raws::RAWS.lock().unwrap(),
ecs,
"scroll_confusion",
raws::SpawnType::Carried { by: player },
0,
);
raws::spawn_named_entity(
&raws::RAWS.lock().unwrap(),
ecs,
"scroll_fireball",
raws::SpawnType::Carried { by: player },
0,
);
return player; return player;
} }