diff --git a/src/ai/encumbrance_system.rs b/src/ai/encumbrance_system.rs index e3693c5..4199a66 100644 --- a/src/ai/encumbrance_system.rs +++ b/src/ai/encumbrance_system.rs @@ -3,7 +3,8 @@ use std::collections::HashMap; use ::specs::prelude::*; use crate::components::{ - AttributeBonus, Attributes, EquipmentChanged, Equipped, InBackpack, Item, Pools, StatusEffect, + AttributeBonus, Attributes, EquipmentChanged, Equipped, InBackpack, Item, Pools, Slow, + StatusEffect, }; use crate::game_log::GameLog; use crate::gamesystem::attr_bonus; @@ -24,6 +25,7 @@ impl<'a> System<'a> for EncumbranceSystem { WriteExpect<'a, GameLog>, ReadStorage<'a, AttributeBonus>, ReadStorage<'a, StatusEffect>, + ReadStorage<'a, Slow>, ); fn run(&mut self, data: Self::SystemData) { @@ -39,6 +41,7 @@ impl<'a> System<'a> for EncumbranceSystem { mut gamelog, attrbonus, statuses, + slowed, ) = data; if equip_dirty.is_empty() { @@ -99,6 +102,14 @@ impl<'a> System<'a> for EncumbranceSystem { } } + // Total up hast/slow + for (status, slow) in (&statuses, &slowed).join() { + if to_update.contains_key(&status.target) { + let totals = to_update.get_mut(&status.target).unwrap(); + totals.initiative += slow.initiative_penalty; + } + } + // Apply the data to Pools for (entity, item) in to_update.iter() { if let Some(pool) = pools.get_mut(*entity) { diff --git a/src/ai/initiative_system.rs b/src/ai/initiative_system.rs index b13d450..f63511e 100644 --- a/src/ai/initiative_system.rs +++ b/src/ai/initiative_system.rs @@ -2,7 +2,8 @@ use ::rltk::{DistanceAlg, Point, RandomNumberGenerator}; use ::specs::prelude::*; use crate::components::{ - Attributes, Duration, EquipmentChanged, Initiative, MyTurn, Pools, Position, StatusEffect, + Attributes, DamageOverTime, Duration, EquipmentChanged, Initiative, MyTurn, Pools, Position, + StatusEffect, }; use crate::RunState; @@ -24,6 +25,7 @@ impl<'a> System<'a> for InitiativeSystem { WriteStorage<'a, Duration>, WriteStorage<'a, EquipmentChanged>, ReadStorage<'a, StatusEffect>, + ReadStorage<'a, DamageOverTime>, ); fn run(&mut self, data: Self::SystemData) { @@ -41,6 +43,7 @@ impl<'a> System<'a> for InitiativeSystem { mut durations, mut dirty, statuses, + dots, ) = data; if *runstate != RunState::Ticking { @@ -91,16 +94,30 @@ impl<'a> System<'a> for InitiativeSystem { } } + // Handle durations if *runstate == RunState::AwaitingInput { + use crate::effects::*; + for (effect_entity, duration, status) in (&entities, &mut durations, &statuses).join() { - duration.turns -= 1; - if duration.turns < 1 { - dirty - .insert(status.target, EquipmentChanged {}) - .expect("Unable to insert EquipmentChanged tag"); - entities - .delete(effect_entity) - .expect("Unable to delete status effect tag entity"); + if entities.is_alive(status.target) { + duration.turns -= 1; + if let Some(dot) = dots.get(effect_entity) { + add_effect( + None, + EffectType::Damage { amount: dot.damage }, + Targets::Single { + target: status.target, + }, + ); + } + if duration.turns < 1 { + dirty + .insert(status.target, EquipmentChanged {}) + .expect("Unable to insert EquipmentChanged tag"); + entities + .delete(effect_entity) + .expect("Unable to delete status effect tag entity"); + } } } } diff --git a/src/effects.rs b/src/effects.rs index 5a86373..b2bf848 100644 --- a/src/effects.rs +++ b/src/effects.rs @@ -62,6 +62,12 @@ pub enum EffectType { name: String, duration: i32, }, + Slow { + initiative_penalty: f32, + }, + DamageOverTime { + damage: i32, + }, } /// Who, or what the effect should affect. @@ -132,6 +138,8 @@ fn tile_effect_hits_entities(effect: &EffectType) -> bool { | EffectType::TeleportTo { .. } | EffectType::AttributeEffect { .. } | EffectType::Mana { .. } + | EffectType::Slow { .. } + | EffectType::DamageOverTime { .. } ) } @@ -169,6 +177,8 @@ fn affect_entity(ecs: &mut World, effect: &EffectSpawner, target: Entity) { EffectType::Confusion { .. } => damage::add_confusion(ecs, effect, target), EffectType::TeleportTo { .. } => movement::apply_teleport(ecs, effect, target), EffectType::AttributeEffect { .. } => damage::attribute_effect(ecs, effect, target), + EffectType::Slow { .. } => damage::slow(ecs, effect, target), + EffectType::DamageOverTime { .. } => damage::damage_over_time(ecs, effect, target), _ => {} } } diff --git a/src/effects/damage.rs b/src/effects/damage.rs index 381d9a1..a155cc8 100644 --- a/src/effects/damage.rs +++ b/src/effects/damage.rs @@ -3,7 +3,9 @@ use ::specs::prelude::*; use ::specs::saveload::{MarkedBuilder, SimpleMarker}; use super::{add_effect, entity_position, EffectSpawner, EffectType, Targets}; -use crate::components::{Attributes, Confusion, Duration, Name, Player, Pools, SerializeMe}; +use crate::components::{ + Attributes, Confusion, DamageOverTime, Duration, Name, Player, Pools, SerializeMe, Slow, +}; use crate::gamesystem::{mana_at_level, player_hp_at_level}; use crate::{colors, EquipmentChanged, GameLog, Map, StatusEffect}; @@ -180,3 +182,33 @@ pub fn attribute_effect(ecs: &mut World, effect: &EffectSpawner, target: Entity) .expect("Failed to insert EquipmentChanged tag"); } } + +pub fn slow(ecs: &mut World, effect: &EffectSpawner, target: Entity) { + if let EffectType::Slow { initiative_penalty } = &effect.effect_type { + ecs.create_entity() + .with(StatusEffect { target }) + .with(Slow { + initiative_penalty: *initiative_penalty, + }) + .with(Duration { turns: 5 }) + .with(if *initiative_penalty > 0.0 { + Name::from("Slowed") + } else { + Name::from("Hasted") + }) + .marked::>() + .build(); + } +} + +pub fn damage_over_time(ecs: &mut World, effect: &EffectSpawner, target: Entity) { + if let EffectType::DamageOverTime { damage } = &effect.effect_type { + ecs.create_entity() + .with(StatusEffect { target }) + .with(DamageOverTime { damage: *damage }) + .with(Duration { turns: 5 }) + .with(Name::from("Damage Over Time")) + .marked::>() + .build(); + } +} diff --git a/src/effects/triggers.rs b/src/effects/triggers.rs index 1761fd7..418c123 100644 --- a/src/effects/triggers.rs +++ b/src/effects/triggers.rs @@ -2,10 +2,10 @@ use ::specs::prelude::*; use super::{add_effect, EffectType, Targets}; use crate::components::{ - AttributeBonus, Confusion, Consumable, Duration, Hidden, InflictsDamage, MagicMapper, Name, - Pools, ProvidesFood, ProvidesHealing, ProvidesIdentification, ProvidesMana, - ProvidesRemoveCurse, SingleActivation, SpawnParticleBurst, SpawnParticleLine, SpellTemplate, - TeachesSpell, TeleportTo, TownPortal, + AttributeBonus, Confusion, Consumable, DamageOverTime, Duration, Hidden, InflictsDamage, + MagicMapper, Name, Pools, ProvidesFood, ProvidesHealing, ProvidesIdentification, ProvidesMana, + ProvidesRemoveCurse, SingleActivation, Slow, SpawnParticleBurst, SpawnParticleLine, + SpellTemplate, TeachesSpell, TeleportTo, TownPortal, }; use crate::effects::{entity_position, targeting}; use crate::raws::find_spell_entity; @@ -290,6 +290,32 @@ fn event_trigger( did_something = true; } + // Slow + if let Some(slow) = ecs.read_storage::().get(entity) { + add_effect( + creator, + EffectType::Slow { + initiative_penalty: slow.initiative_penalty, + }, + targets.clone(), + ); + + did_something = true; + } + + // Damage Over Time + if let Some(damage) = ecs.read_storage::().get(entity) { + add_effect( + creator, + EffectType::DamageOverTime { + damage: damage.damage, + }, + targets.clone(), + ); + + did_something = true; + } + did_something }