Implement Slow and DamageOverTime effects

This commit is contained in:
Timothy Warren 2022-01-25 14:02:40 -05:00
parent 1fb4bf293f
commit 2f0b9b4535
5 changed files with 111 additions and 15 deletions

View File

@ -3,7 +3,8 @@ use std::collections::HashMap;
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::{ 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::game_log::GameLog;
use crate::gamesystem::attr_bonus; use crate::gamesystem::attr_bonus;
@ -24,6 +25,7 @@ impl<'a> System<'a> for EncumbranceSystem {
WriteExpect<'a, GameLog>, WriteExpect<'a, GameLog>,
ReadStorage<'a, AttributeBonus>, ReadStorage<'a, AttributeBonus>,
ReadStorage<'a, StatusEffect>, ReadStorage<'a, StatusEffect>,
ReadStorage<'a, Slow>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
@ -39,6 +41,7 @@ impl<'a> System<'a> for EncumbranceSystem {
mut gamelog, mut gamelog,
attrbonus, attrbonus,
statuses, statuses,
slowed,
) = data; ) = data;
if equip_dirty.is_empty() { 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 // Apply the data to Pools
for (entity, item) in to_update.iter() { for (entity, item) in to_update.iter() {
if let Some(pool) = pools.get_mut(*entity) { if let Some(pool) = pools.get_mut(*entity) {

View File

@ -2,7 +2,8 @@ use ::rltk::{DistanceAlg, Point, RandomNumberGenerator};
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::{ use crate::components::{
Attributes, Duration, EquipmentChanged, Initiative, MyTurn, Pools, Position, StatusEffect, Attributes, DamageOverTime, Duration, EquipmentChanged, Initiative, MyTurn, Pools, Position,
StatusEffect,
}; };
use crate::RunState; use crate::RunState;
@ -24,6 +25,7 @@ impl<'a> System<'a> for InitiativeSystem {
WriteStorage<'a, Duration>, WriteStorage<'a, Duration>,
WriteStorage<'a, EquipmentChanged>, WriteStorage<'a, EquipmentChanged>,
ReadStorage<'a, StatusEffect>, ReadStorage<'a, StatusEffect>,
ReadStorage<'a, DamageOverTime>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
@ -41,6 +43,7 @@ impl<'a> System<'a> for InitiativeSystem {
mut durations, mut durations,
mut dirty, mut dirty,
statuses, statuses,
dots,
) = data; ) = data;
if *runstate != RunState::Ticking { if *runstate != RunState::Ticking {
@ -91,9 +94,22 @@ impl<'a> System<'a> for InitiativeSystem {
} }
} }
// Handle durations
if *runstate == RunState::AwaitingInput { if *runstate == RunState::AwaitingInput {
use crate::effects::*;
for (effect_entity, duration, status) in (&entities, &mut durations, &statuses).join() { for (effect_entity, duration, status) in (&entities, &mut durations, &statuses).join() {
if entities.is_alive(status.target) {
duration.turns -= 1; 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 { if duration.turns < 1 {
dirty dirty
.insert(status.target, EquipmentChanged {}) .insert(status.target, EquipmentChanged {})
@ -105,4 +121,5 @@ impl<'a> System<'a> for InitiativeSystem {
} }
} }
} }
}
} }

View File

@ -62,6 +62,12 @@ pub enum EffectType {
name: String, name: String,
duration: i32, duration: i32,
}, },
Slow {
initiative_penalty: f32,
},
DamageOverTime {
damage: i32,
},
} }
/// Who, or what the effect should affect. /// Who, or what the effect should affect.
@ -132,6 +138,8 @@ fn tile_effect_hits_entities(effect: &EffectType) -> bool {
| EffectType::TeleportTo { .. } | EffectType::TeleportTo { .. }
| EffectType::AttributeEffect { .. } | EffectType::AttributeEffect { .. }
| EffectType::Mana { .. } | 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::Confusion { .. } => damage::add_confusion(ecs, effect, target),
EffectType::TeleportTo { .. } => movement::apply_teleport(ecs, effect, target), EffectType::TeleportTo { .. } => movement::apply_teleport(ecs, effect, target),
EffectType::AttributeEffect { .. } => damage::attribute_effect(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),
_ => {} _ => {}
} }
} }

View File

@ -3,7 +3,9 @@ use ::specs::prelude::*;
use ::specs::saveload::{MarkedBuilder, SimpleMarker}; use ::specs::saveload::{MarkedBuilder, SimpleMarker};
use super::{add_effect, entity_position, EffectSpawner, EffectType, Targets}; 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::gamesystem::{mana_at_level, player_hp_at_level};
use crate::{colors, EquipmentChanged, GameLog, Map, StatusEffect}; 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"); .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::<SimpleMarker<SerializeMe>>()
.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::<SimpleMarker<SerializeMe>>()
.build();
}
}

View File

@ -2,10 +2,10 @@ use ::specs::prelude::*;
use super::{add_effect, EffectType, Targets}; use super::{add_effect, EffectType, Targets};
use crate::components::{ use crate::components::{
AttributeBonus, Confusion, Consumable, Duration, Hidden, InflictsDamage, MagicMapper, Name, AttributeBonus, Confusion, Consumable, DamageOverTime, Duration, Hidden, InflictsDamage,
Pools, ProvidesFood, ProvidesHealing, ProvidesIdentification, ProvidesMana, MagicMapper, Name, Pools, ProvidesFood, ProvidesHealing, ProvidesIdentification, ProvidesMana,
ProvidesRemoveCurse, SingleActivation, SpawnParticleBurst, SpawnParticleLine, SpellTemplate, ProvidesRemoveCurse, SingleActivation, Slow, SpawnParticleBurst, SpawnParticleLine,
TeachesSpell, TeleportTo, TownPortal, SpellTemplate, TeachesSpell, TeleportTo, TownPortal,
}; };
use crate::effects::{entity_position, targeting}; use crate::effects::{entity_position, targeting};
use crate::raws::find_spell_entity; use crate::raws::find_spell_entity;
@ -290,6 +290,32 @@ fn event_trigger(
did_something = true; did_something = true;
} }
// Slow
if let Some(slow) = ecs.read_storage::<Slow>().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::<DamageOverTime>().get(entity) {
add_effect(
creator,
EffectType::DamageOverTime {
damage: damage.damage,
},
targets.clone(),
);
did_something = true;
}
did_something did_something
} }