Simplify ItemUseSystem and TriggerSystem by refactoring into piecs of the effect module
This commit is contained in:
parent
0f6755b35f
commit
0f3903e456
@ -1,6 +1,9 @@
|
||||
mod damage;
|
||||
mod hunger;
|
||||
mod movement;
|
||||
mod particles;
|
||||
mod targeting;
|
||||
mod triggers;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Mutex;
|
||||
@ -9,7 +12,6 @@ use ::rltk::{FontCharType, RGB};
|
||||
use ::specs::prelude::*;
|
||||
pub use targeting::*;
|
||||
|
||||
use crate::effects::particles::particle_to_tile;
|
||||
use crate::spatial;
|
||||
|
||||
lazy_static! {
|
||||
@ -28,6 +30,25 @@ pub enum EffectType {
|
||||
lifespan: f32,
|
||||
},
|
||||
EntityDeath,
|
||||
ItemUse {
|
||||
item: Entity,
|
||||
},
|
||||
WellFed,
|
||||
Healing {
|
||||
amount: i32,
|
||||
},
|
||||
Confusion {
|
||||
turns: i32,
|
||||
},
|
||||
TriggerFire {
|
||||
trigger: Entity,
|
||||
},
|
||||
TeleportTo {
|
||||
x: i32,
|
||||
y: i32,
|
||||
depth: i32,
|
||||
player_only: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -65,23 +86,33 @@ pub fn run_effects_queue(ecs: &mut World) {
|
||||
}
|
||||
|
||||
fn target_applicator(ecs: &mut World, effect: &EffectSpawner) {
|
||||
match &effect.targets {
|
||||
Targets::Tile { tile_idx } => affect_tile(ecs, effect, *tile_idx),
|
||||
Targets::Tiles { tiles } => tiles
|
||||
.iter()
|
||||
.for_each(|tile_idx| affect_tile(ecs, effect, *tile_idx)),
|
||||
Targets::Single { target } => affect_entity(ecs, effect, *target),
|
||||
Targets::TargetList { targets } => targets
|
||||
.iter()
|
||||
.for_each(|entity| affect_entity(ecs, effect, *entity)),
|
||||
if let EffectType::ItemUse { item } = effect.effect_type {
|
||||
triggers::item_trigger(effect.creator, item, &effect.targets, ecs);
|
||||
} else if let EffectType::TriggerFire { trigger } = effect.effect_type {
|
||||
triggers::trigger(effect.creator, trigger, &effect.targets, ecs);
|
||||
} else {
|
||||
match &effect.targets {
|
||||
Targets::Tile { tile_idx } => affect_tile(ecs, effect, *tile_idx),
|
||||
Targets::Tiles { tiles } => tiles
|
||||
.iter()
|
||||
.for_each(|tile_idx| affect_tile(ecs, effect, *tile_idx)),
|
||||
Targets::Single { target } => affect_entity(ecs, effect, *target),
|
||||
Targets::TargetList { targets } => targets
|
||||
.iter()
|
||||
.for_each(|entity| affect_entity(ecs, effect, *entity)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tile_effect_hits_entities(effect: &EffectType) -> bool {
|
||||
match effect {
|
||||
EffectType::Damage { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(
|
||||
effect,
|
||||
EffectType::Damage { .. }
|
||||
| EffectType::WellFed
|
||||
| EffectType::Healing { .. }
|
||||
| EffectType::Confusion { .. }
|
||||
| EffectType::TeleportTo { .. }
|
||||
)
|
||||
}
|
||||
|
||||
fn affect_tile(ecs: &mut World, effect: &EffectSpawner, tile_idx: i32) {
|
||||
@ -93,7 +124,7 @@ fn affect_tile(ecs: &mut World, effect: &EffectSpawner, tile_idx: i32) {
|
||||
|
||||
match &effect.effect_type {
|
||||
EffectType::Bloodstain => damage::bloodstain(ecs, tile_idx),
|
||||
EffectType::Particle { .. } => particle_to_tile(ecs, tile_idx, effect),
|
||||
EffectType::Particle { .. } => particles::particle_to_tile(ecs, tile_idx, effect),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -109,8 +140,13 @@ fn affect_entity(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||
}
|
||||
EffectType::Particle { .. } => {
|
||||
if let Some(pos) = entity_position(ecs, target) {
|
||||
particle_to_tile(ecs, pos, effect)
|
||||
particles::particle_to_tile(ecs, pos, effect)
|
||||
}
|
||||
}
|
||||
EffectType::WellFed => hunger::well_fed(ecs, effect, target),
|
||||
EffectType::Healing { .. } => damage::heal_damage(ecs, effect, target),
|
||||
EffectType::Confusion { .. } => damage::add_confusion(ecs, effect, target),
|
||||
EffectType::TeleportTo { .. } => movement::apply_teleport(ecs, effect, target),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use ::rltk::Point;
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use super::{add_effect, entity_position, EffectSpawner, EffectType, Targets};
|
||||
use crate::components::{Attributes, Player, Pools};
|
||||
use crate::components::{Attributes, Confusion, Player, Pools};
|
||||
use crate::gamesystem::{mana_at_level, player_hp_at_level};
|
||||
use crate::{colors, GameLog, Map};
|
||||
|
||||
@ -107,3 +107,31 @@ pub fn death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn heal_damage(ecs: &mut World, heal: &EffectSpawner, target: Entity) {
|
||||
let mut pools = ecs.write_storage::<Pools>();
|
||||
if let Some(pool) = pools.get_mut(target) {
|
||||
if let EffectType::Healing { amount } = heal.effect_type {
|
||||
pool.hit_points.current =
|
||||
i32::min(pool.hit_points.max, pool.hit_points.current + amount);
|
||||
add_effect(
|
||||
None,
|
||||
EffectType::Particle {
|
||||
glyph: ::rltk::to_cp437('‼'),
|
||||
fg: colors::GREEN,
|
||||
bg: colors::BLACK,
|
||||
lifespan: 200.0,
|
||||
},
|
||||
Targets::Single { target },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 make target confused");
|
||||
}
|
||||
}
|
||||
|
11
src/effects/hunger.rs
Normal file
11
src/effects/hunger.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use super::EffectSpawner;
|
||||
use crate::components::{HungerClock, HungerState};
|
||||
|
||||
pub fn well_fed(ecs: &mut World, _damage: &EffectSpawner, target: Entity) {
|
||||
if let Some(hc) = ecs.write_storage::<HungerClock>().get_mut(target) {
|
||||
hc.state = HungerState::WellFed;
|
||||
hc.duration = 20;
|
||||
}
|
||||
}
|
29
src/effects/movement.rs
Normal file
29
src/effects/movement.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use super::{EffectSpawner, EffectType};
|
||||
use crate::components::ApplyTeleport;
|
||||
|
||||
pub fn apply_teleport(ecs: &mut World, destination: &EffectSpawner, target: Entity) {
|
||||
let player_entity = ecs.fetch::<Entity>();
|
||||
if let EffectType::TeleportTo {
|
||||
x,
|
||||
y,
|
||||
depth,
|
||||
player_only,
|
||||
} = &destination.effect_type
|
||||
{
|
||||
if !*player_only || target == *player_entity {
|
||||
let mut apply_teleport = ecs.write_storage::<ApplyTeleport>();
|
||||
apply_teleport
|
||||
.insert(
|
||||
target,
|
||||
ApplyTeleport {
|
||||
dest_x: *x,
|
||||
dest_y: *y,
|
||||
dest_depth: *depth,
|
||||
},
|
||||
)
|
||||
.expect("Unable to insert intent to teleport");
|
||||
}
|
||||
}
|
||||
}
|
@ -12,3 +12,13 @@ pub fn entity_position(ecs: &World, target: Entity) -> Option<i32> {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn aoe_tiles(map: &Map, target: ::rltk::Point, radius: i32) -> Vec<i32> {
|
||||
let mut blast_tiles = ::rltk::field_of_view(target, radius, &*map);
|
||||
blast_tiles.retain(|p| p.x > 0 && p.x < map.width - 1 && p.y > 0 && p.y < map.height - 1);
|
||||
let mut result = Vec::new();
|
||||
for t in blast_tiles.iter() {
|
||||
result.push(map.xy_idx(t.x, t.y) as i32);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
116
src/effects/triggers.rs
Normal file
116
src/effects/triggers.rs
Normal file
@ -0,0 +1,116 @@
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use super::{add_effect, EffectType, Targets};
|
||||
use crate::components::{
|
||||
Confusion, Consumable, Hidden, InflictsDamage, MagicMapper, Name, ProvidesFood,
|
||||
ProvidesHealing, SingleActivation, TeleportTo, TownPortal,
|
||||
};
|
||||
use crate::{GameLog, Map, RunState};
|
||||
|
||||
pub fn item_trigger(creator: Option<Entity>, item: Entity, targets: &Targets, ecs: &mut World) {
|
||||
// Use the item via the generic system
|
||||
event_trigger(creator, item, targets, ecs);
|
||||
|
||||
// If it was a consumable, then it gets deleted
|
||||
if ecs.read_storage::<Consumable>().get(item).is_some() {
|
||||
ecs.entities()
|
||||
.delete(item)
|
||||
.expect("Failed to delete consumable item");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trigger(creator: Option<Entity>, trigger: Entity, targets: &Targets, ecs: &mut World) {
|
||||
// The triggering item is no longer hidden
|
||||
ecs.write_storage::<Hidden>().remove(trigger);
|
||||
|
||||
// Use the item via the generic system
|
||||
event_trigger(creator, trigger, targets, ecs);
|
||||
|
||||
// If it was a single activation, then it gets deleted
|
||||
if ecs
|
||||
.read_storage::<SingleActivation>()
|
||||
.get(trigger)
|
||||
.is_some()
|
||||
{
|
||||
ecs.entities()
|
||||
.delete(trigger)
|
||||
.expect("Failed to delete SingleActivation tag");
|
||||
}
|
||||
}
|
||||
|
||||
fn event_trigger(creator: Option<Entity>, entity: Entity, targets: &Targets, ecs: &mut World) {
|
||||
let mut gamelog = ecs.fetch_mut::<GameLog>();
|
||||
|
||||
// Providing food
|
||||
if ecs.read_storage::<ProvidesFood>().get(entity).is_some() {
|
||||
add_effect(creator, EffectType::WellFed, targets.clone());
|
||||
let names = ecs.read_storage::<Name>();
|
||||
gamelog.append(format!("You eat the {}.", names.get(entity).unwrap().name));
|
||||
}
|
||||
|
||||
// Magic mapper
|
||||
if ecs.read_storage::<MagicMapper>().get(entity).is_some() {
|
||||
let mut runstate = ecs.fetch_mut::<RunState>();
|
||||
gamelog.append("The map is revealed to you!");
|
||||
*runstate = RunState::MagicMapReveal { row: 0 };
|
||||
}
|
||||
|
||||
// Town Portal
|
||||
if ecs.read_storage::<TownPortal>().get(entity).is_some() {
|
||||
let map = ecs.fetch::<Map>();
|
||||
if map.depth == 1 {
|
||||
gamelog.append("You are already in town, so the scroll does nothing.");
|
||||
} else {
|
||||
gamelog.append("You are teleported back to town!");
|
||||
let mut runstate = ecs.fetch_mut::<RunState>();
|
||||
*runstate = RunState::TownPortal;
|
||||
}
|
||||
}
|
||||
|
||||
// Healing
|
||||
if let Some(heal) = ecs.read_storage::<ProvidesHealing>().get(entity) {
|
||||
add_effect(
|
||||
creator,
|
||||
EffectType::Healing {
|
||||
amount: heal.heal_amount,
|
||||
},
|
||||
targets.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
// Damage
|
||||
if let Some(damage) = ecs.read_storage::<InflictsDamage>().get(entity) {
|
||||
add_effect(
|
||||
creator,
|
||||
EffectType::Damage {
|
||||
amount: damage.damage,
|
||||
},
|
||||
targets.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
// Confusion
|
||||
if let Some(confusion) = ecs.read_storage::<Confusion>().get(entity) {
|
||||
add_effect(
|
||||
creator,
|
||||
EffectType::Confusion {
|
||||
turns: confusion.turns,
|
||||
},
|
||||
targets.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
// Teleport
|
||||
if let Some(teleport) = ecs.read_storage::<TeleportTo>().get(entity) {
|
||||
add_effect(
|
||||
creator,
|
||||
EffectType::TeleportTo {
|
||||
x: teleport.x,
|
||||
y: teleport.y,
|
||||
depth: teleport.depth,
|
||||
player_only: teleport.player_only,
|
||||
},
|
||||
targets.clone(),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,13 +1,8 @@
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use crate::components::{
|
||||
AreaOfEffect, Confusion, Consumable, EquipmentChanged, HungerClock, HungerState,
|
||||
IdentifiedItem, InflictsDamage, MagicMapper, Name, Pools, Position, ProvidesFood,
|
||||
ProvidesHealing, SufferDamage, TownPortal, WantsToUseItem,
|
||||
};
|
||||
use crate::game_log::GameLog;
|
||||
use crate::particle_system::ParticleBuilder;
|
||||
use crate::{colors, spatial, Map, RunState};
|
||||
use crate::components::{AreaOfEffect, EquipmentChanged, IdentifiedItem, Name, WantsToUseItem};
|
||||
use crate::effects::{add_effect, aoe_tiles, EffectType, Targets};
|
||||
use crate::Map;
|
||||
|
||||
pub struct ItemUseSystem {}
|
||||
|
||||
@ -15,26 +10,12 @@ impl<'a> System<'a> for ItemUseSystem {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
ReadExpect<'a, Entity>,
|
||||
WriteExpect<'a, GameLog>,
|
||||
WriteExpect<'a, Map>,
|
||||
Entities<'a>,
|
||||
WriteStorage<'a, WantsToUseItem>,
|
||||
ReadStorage<'a, Name>,
|
||||
ReadStorage<'a, Consumable>,
|
||||
ReadStorage<'a, ProvidesHealing>,
|
||||
ReadStorage<'a, InflictsDamage>,
|
||||
WriteStorage<'a, Pools>,
|
||||
WriteStorage<'a, SufferDamage>,
|
||||
ReadStorage<'a, AreaOfEffect>,
|
||||
WriteStorage<'a, Confusion>,
|
||||
WriteExpect<'a, ParticleBuilder>,
|
||||
ReadStorage<'a, Position>,
|
||||
ReadStorage<'a, ProvidesFood>,
|
||||
WriteStorage<'a, HungerClock>,
|
||||
ReadStorage<'a, MagicMapper>,
|
||||
WriteExpect<'a, RunState>,
|
||||
WriteStorage<'a, EquipmentChanged>,
|
||||
ReadStorage<'a, TownPortal>,
|
||||
WriteStorage<'a, IdentifiedItem>,
|
||||
);
|
||||
|
||||
@ -42,26 +23,12 @@ impl<'a> System<'a> for ItemUseSystem {
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
let (
|
||||
player_entity,
|
||||
mut gamelog,
|
||||
map,
|
||||
entities,
|
||||
mut wants_use,
|
||||
names,
|
||||
consumables,
|
||||
healing,
|
||||
inflict_damage,
|
||||
mut combat_stats,
|
||||
mut suffer_damage,
|
||||
aoe,
|
||||
mut confused,
|
||||
mut particle_builder,
|
||||
positions,
|
||||
provides_food,
|
||||
mut hunger_clocks,
|
||||
magic_mapper,
|
||||
mut runstate,
|
||||
mut dirty,
|
||||
town_portal,
|
||||
mut identified_item,
|
||||
) = data;
|
||||
|
||||
@ -69,46 +36,6 @@ impl<'a> System<'a> for ItemUseSystem {
|
||||
dirty
|
||||
.insert(entity, EquipmentChanged {})
|
||||
.expect("Unable to insert equipment change");
|
||||
let mut used_item = true;
|
||||
|
||||
// Targeting
|
||||
let mut targets: Vec<Entity> = Vec::new();
|
||||
match useitem.target {
|
||||
None => {
|
||||
targets.push(*player_entity);
|
||||
}
|
||||
Some(target) => {
|
||||
match aoe.get(useitem.item) {
|
||||
None => {
|
||||
// Single target in tile
|
||||
let idx = map.xy_idx(target.x, target.y);
|
||||
spatial::for_each_tile_content(idx, |mob| targets.push(mob));
|
||||
}
|
||||
Some(area_effect) => {
|
||||
// AoE
|
||||
let mut blast_tiles =
|
||||
rltk::field_of_view(target, area_effect.radius, &*map);
|
||||
blast_tiles.retain(|p| {
|
||||
p.x > 0 && p.x < map.width - 1 && p.y > 0 && p.y < map.height - 1
|
||||
});
|
||||
|
||||
for tile_idx in blast_tiles.iter() {
|
||||
let idx = map.xy_idx(tile_idx.x, tile_idx.y);
|
||||
spatial::for_each_tile_content(idx, |mob| targets.push(mob));
|
||||
|
||||
particle_builder.request(
|
||||
tile_idx.x,
|
||||
tile_idx.y,
|
||||
colors::ORANGE,
|
||||
colors::BLACK,
|
||||
rltk::to_cp437('░'),
|
||||
200.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Identify
|
||||
if entity == *player_entity {
|
||||
@ -122,173 +49,27 @@ impl<'a> System<'a> for ItemUseSystem {
|
||||
.expect("Unable to identify item");
|
||||
}
|
||||
|
||||
// If it is edible, eat it!
|
||||
match provides_food.get(useitem.item) {
|
||||
None => {}
|
||||
Some(_) => {
|
||||
used_item = true;
|
||||
let target = targets[0];
|
||||
|
||||
if let Some(hc) = hunger_clocks.get_mut(target) {
|
||||
hc.state = HungerState::WellFed;
|
||||
hc.duration = 20;
|
||||
|
||||
gamelog.append(format!(
|
||||
"You eat the {}.",
|
||||
names.get(useitem.item).unwrap().name
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If its a magic mapper...
|
||||
match magic_mapper.get(useitem.item) {
|
||||
None => {}
|
||||
Some(_) => {
|
||||
used_item = true;
|
||||
gamelog.append("The map is revealed to you!");
|
||||
|
||||
*runstate = RunState::MagicMapReveal { row: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
// If it's a town portal...
|
||||
if town_portal.get(useitem.item).is_some() {
|
||||
if map.depth == 1 {
|
||||
gamelog.append("You are already in town, so the scroll does nothing");
|
||||
} else {
|
||||
used_item = true;
|
||||
gamelog.append("You are teleported back to town!");
|
||||
|
||||
*runstate = RunState::TownPortal;
|
||||
}
|
||||
}
|
||||
|
||||
// If the item heals, apply the healing
|
||||
match healing.get(useitem.item) {
|
||||
None => {}
|
||||
Some(healer) => {
|
||||
used_item = false;
|
||||
|
||||
for target in targets.iter() {
|
||||
if let Some(stats) = combat_stats.get_mut(*target) {
|
||||
stats.hit_points.current = i32::min(
|
||||
stats.hit_points.max,
|
||||
stats.hit_points.current + healer.heal_amount,
|
||||
);
|
||||
if entity == *player_entity {
|
||||
gamelog.append(format!(
|
||||
"You drink the {}, healing {} hp.",
|
||||
names.get(useitem.item).unwrap().name,
|
||||
healer.heal_amount
|
||||
));
|
||||
// Call the effects system
|
||||
add_effect(
|
||||
Some(entity),
|
||||
EffectType::ItemUse { item: useitem.item },
|
||||
match useitem.target {
|
||||
None => Targets::Single {
|
||||
target: *player_entity,
|
||||
},
|
||||
Some(target) => {
|
||||
if let Some(aoe) = aoe.get(useitem.item) {
|
||||
Targets::Tiles {
|
||||
tiles: aoe_tiles(&*map, target, aoe.radius),
|
||||
}
|
||||
|
||||
used_item = true;
|
||||
|
||||
// Visually show healing
|
||||
if let Some(pos) = positions.get(*target) {
|
||||
particle_builder.request(
|
||||
pos.x,
|
||||
pos.y,
|
||||
colors::GREEN,
|
||||
colors::BLACK,
|
||||
rltk::to_cp437('♥'),
|
||||
200.0,
|
||||
);
|
||||
} else {
|
||||
Targets::Tile {
|
||||
tile_idx: map.xy_idx(target.x, target.y) as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If it inflicts damage, apply it to the target cell
|
||||
match inflict_damage.get(useitem.item) {
|
||||
None => {}
|
||||
Some(damage) => {
|
||||
used_item = false;
|
||||
|
||||
for mob in targets.iter() {
|
||||
SufferDamage::new_damage(&mut suffer_damage, *mob, damage.damage, true);
|
||||
if entity == *player_entity {
|
||||
let mob_name = names.get(*mob).unwrap();
|
||||
let item_name = names.get(useitem.item).unwrap();
|
||||
|
||||
gamelog.append(format!(
|
||||
"You use {} on {}, inflicting {} hp.",
|
||||
item_name.name, mob_name.name, damage.damage
|
||||
));
|
||||
|
||||
if let Some(pos) = positions.get(*mob) {
|
||||
particle_builder.request(
|
||||
pos.x,
|
||||
pos.y,
|
||||
colors::RED,
|
||||
colors::BLACK,
|
||||
rltk::to_cp437('‼'),
|
||||
200.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
used_item = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Can it pass along confusion? Note the use of scopes
|
||||
// to escape from the borrow checker!
|
||||
let mut add_confusion = Vec::new();
|
||||
{
|
||||
match confused.get(useitem.item) {
|
||||
None => {}
|
||||
Some(confusion) => {
|
||||
used_item = false;
|
||||
|
||||
for mob in targets.iter() {
|
||||
add_confusion.push((*mob, confusion.turns));
|
||||
if entity == *player_entity {
|
||||
let mob_name = names.get(*mob).unwrap();
|
||||
let item_name = names.get(useitem.item).unwrap();
|
||||
|
||||
gamelog.append(format!(
|
||||
"You use {} on {}, confusing them.",
|
||||
item_name.name, mob_name.name
|
||||
));
|
||||
|
||||
if let Some(pos) = positions.get(*mob) {
|
||||
particle_builder.request(
|
||||
pos.x,
|
||||
pos.y,
|
||||
colors::MAGENTA,
|
||||
colors::BLACK,
|
||||
rltk::to_cp437('?'),
|
||||
200.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for mob in add_confusion.iter() {
|
||||
confused
|
||||
.insert(mob.0, Confusion { turns: mob.1 })
|
||||
.expect("Unable to add confused status");
|
||||
}
|
||||
|
||||
// If it's a consumable, delete it on use
|
||||
if used_item {
|
||||
let consumable = consumables.get(useitem.item);
|
||||
match consumable {
|
||||
None => {}
|
||||
Some(_) => {
|
||||
entities
|
||||
.delete(useitem.item)
|
||||
.expect("Failed to consume item");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
wants_use.clear();
|
||||
|
@ -1,13 +1,9 @@
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use crate::components::{
|
||||
ApplyTeleport, EntityMoved, EntryTrigger, Hidden, InflictsDamage, Name, Position,
|
||||
SingleActivation, TeleportTo,
|
||||
};
|
||||
use crate::effects::{add_effect, EffectType, Targets};
|
||||
use crate::components::{AreaOfEffect, EntityMoved, EntryTrigger, Name, Position};
|
||||
use crate::effects::{add_effect, aoe_tiles, EffectType, Targets};
|
||||
use crate::game_log::GameLog;
|
||||
use crate::particle_system::ParticleBuilder;
|
||||
use crate::{colors, spatial, Map};
|
||||
use crate::{spatial, Map};
|
||||
|
||||
pub struct TriggerSystem {}
|
||||
|
||||
@ -18,16 +14,10 @@ impl<'a> System<'a> for TriggerSystem {
|
||||
WriteStorage<'a, EntityMoved>,
|
||||
ReadStorage<'a, Position>,
|
||||
ReadStorage<'a, EntryTrigger>,
|
||||
WriteStorage<'a, Hidden>,
|
||||
ReadStorage<'a, Name>,
|
||||
Entities<'a>,
|
||||
WriteExpect<'a, GameLog>,
|
||||
ReadStorage<'a, InflictsDamage>,
|
||||
WriteExpect<'a, ParticleBuilder>,
|
||||
ReadStorage<'a, SingleActivation>,
|
||||
ReadStorage<'a, TeleportTo>,
|
||||
WriteStorage<'a, ApplyTeleport>,
|
||||
ReadExpect<'a, Entity>,
|
||||
ReadStorage<'a, AreaOfEffect>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
@ -36,20 +26,13 @@ impl<'a> System<'a> for TriggerSystem {
|
||||
mut entity_moved,
|
||||
position,
|
||||
entry_trigger,
|
||||
mut hidden,
|
||||
names,
|
||||
entities,
|
||||
mut log,
|
||||
inflicts_damage,
|
||||
mut particle_builder,
|
||||
single_activation,
|
||||
teleporters,
|
||||
mut apply_teleport,
|
||||
player_entity,
|
||||
area_of_effect,
|
||||
) = data;
|
||||
|
||||
// Iterate the entities that moved and their final position
|
||||
let mut remove_entities: Vec<Entity> = Vec::new();
|
||||
for (entity, mut _entity_moved, pos) in (&entities, &mut entity_moved, &position).join() {
|
||||
let idx = map.xy_idx(pos.x, pos.y);
|
||||
|
||||
@ -64,62 +47,30 @@ impl<'a> System<'a> for TriggerSystem {
|
||||
log.append(format!("{} triggers!", &name.name));
|
||||
}
|
||||
|
||||
// The trap is no longer hidden
|
||||
hidden.remove(entity_id);
|
||||
|
||||
// If the trap is damage inflicting, do it
|
||||
if let Some(damage) = inflicts_damage.get(entity_id) {
|
||||
particle_builder.request(
|
||||
pos.x,
|
||||
pos.y,
|
||||
colors::ORANGE,
|
||||
colors::BLACK,
|
||||
rltk::to_cp437('‼'),
|
||||
200.0,
|
||||
);
|
||||
|
||||
add_effect(
|
||||
None,
|
||||
EffectType::Damage {
|
||||
amount: damage.damage,
|
||||
},
|
||||
Targets::Single { target: entity },
|
||||
)
|
||||
}
|
||||
|
||||
// If it's a teleporter, then do that
|
||||
if let Some(teleport) = teleporters.get(entity_id) {
|
||||
if !teleport.player_only || entity == *player_entity {
|
||||
apply_teleport
|
||||
.insert(
|
||||
entity,
|
||||
ApplyTeleport {
|
||||
dest_x: teleport.x,
|
||||
dest_y: teleport.y,
|
||||
dest_depth: teleport.depth,
|
||||
},
|
||||
)
|
||||
.expect("Unable to insert intent to teleport");
|
||||
}
|
||||
}
|
||||
|
||||
// If it is single activation, it needs to be removed
|
||||
if single_activation.get(entity_id).is_some() {
|
||||
remove_entities.push(entity_id);
|
||||
}
|
||||
// Call the effects system
|
||||
add_effect(
|
||||
Some(entity),
|
||||
EffectType::TriggerFire { trigger: entity_id },
|
||||
if let Some(aoe) = area_of_effect.get(entity_id) {
|
||||
Targets::Tiles {
|
||||
tiles: aoe_tiles(
|
||||
&*map,
|
||||
::rltk::Point::from(*pos),
|
||||
aoe.radius,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
Targets::Tile {
|
||||
tile_idx: idx as i32,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Remove any single activation traps
|
||||
for trap in remove_entities.iter() {
|
||||
entities
|
||||
.delete(*trap)
|
||||
.expect("Unable to remove single activation entity");
|
||||
}
|
||||
|
||||
// Remove all entity movement markers
|
||||
entity_moved.clear();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user