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 damage;
|
||||||
|
mod hunger;
|
||||||
|
mod movement;
|
||||||
mod particles;
|
mod particles;
|
||||||
mod targeting;
|
mod targeting;
|
||||||
|
mod triggers;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
@ -9,7 +12,6 @@ use ::rltk::{FontCharType, RGB};
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
pub use targeting::*;
|
pub use targeting::*;
|
||||||
|
|
||||||
use crate::effects::particles::particle_to_tile;
|
|
||||||
use crate::spatial;
|
use crate::spatial;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -28,6 +30,25 @@ pub enum EffectType {
|
|||||||
lifespan: f32,
|
lifespan: f32,
|
||||||
},
|
},
|
||||||
EntityDeath,
|
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)]
|
#[derive(Clone)]
|
||||||
@ -65,6 +86,11 @@ pub fn run_effects_queue(ecs: &mut World) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn target_applicator(ecs: &mut World, effect: &EffectSpawner) {
|
fn target_applicator(ecs: &mut World, effect: &EffectSpawner) {
|
||||||
|
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 {
|
match &effect.targets {
|
||||||
Targets::Tile { tile_idx } => affect_tile(ecs, effect, *tile_idx),
|
Targets::Tile { tile_idx } => affect_tile(ecs, effect, *tile_idx),
|
||||||
Targets::Tiles { tiles } => tiles
|
Targets::Tiles { tiles } => tiles
|
||||||
@ -76,12 +102,17 @@ fn target_applicator(ecs: &mut World, effect: &EffectSpawner) {
|
|||||||
.for_each(|entity| affect_entity(ecs, effect, *entity)),
|
.for_each(|entity| affect_entity(ecs, effect, *entity)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn tile_effect_hits_entities(effect: &EffectType) -> bool {
|
fn tile_effect_hits_entities(effect: &EffectType) -> bool {
|
||||||
match effect {
|
matches!(
|
||||||
EffectType::Damage { .. } => true,
|
effect,
|
||||||
_ => false,
|
EffectType::Damage { .. }
|
||||||
}
|
| EffectType::WellFed
|
||||||
|
| EffectType::Healing { .. }
|
||||||
|
| EffectType::Confusion { .. }
|
||||||
|
| EffectType::TeleportTo { .. }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn affect_tile(ecs: &mut World, effect: &EffectSpawner, tile_idx: i32) {
|
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 {
|
match &effect.effect_type {
|
||||||
EffectType::Bloodstain => damage::bloodstain(ecs, tile_idx),
|
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 { .. } => {
|
EffectType::Particle { .. } => {
|
||||||
if let Some(pos) = entity_position(ecs, target) {
|
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 ::specs::prelude::*;
|
||||||
|
|
||||||
use super::{add_effect, entity_position, EffectSpawner, EffectType, Targets};
|
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::gamesystem::{mana_at_level, player_hp_at_level};
|
||||||
use crate::{colors, GameLog, Map};
|
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
|
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 ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{
|
use crate::components::{AreaOfEffect, EquipmentChanged, IdentifiedItem, Name, WantsToUseItem};
|
||||||
AreaOfEffect, Confusion, Consumable, EquipmentChanged, HungerClock, HungerState,
|
use crate::effects::{add_effect, aoe_tiles, EffectType, Targets};
|
||||||
IdentifiedItem, InflictsDamage, MagicMapper, Name, Pools, Position, ProvidesFood,
|
use crate::Map;
|
||||||
ProvidesHealing, SufferDamage, TownPortal, WantsToUseItem,
|
|
||||||
};
|
|
||||||
use crate::game_log::GameLog;
|
|
||||||
use crate::particle_system::ParticleBuilder;
|
|
||||||
use crate::{colors, spatial, Map, RunState};
|
|
||||||
|
|
||||||
pub struct ItemUseSystem {}
|
pub struct ItemUseSystem {}
|
||||||
|
|
||||||
@ -15,26 +10,12 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
type SystemData = (
|
type SystemData = (
|
||||||
ReadExpect<'a, Entity>,
|
ReadExpect<'a, Entity>,
|
||||||
WriteExpect<'a, GameLog>,
|
|
||||||
WriteExpect<'a, Map>,
|
WriteExpect<'a, Map>,
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
WriteStorage<'a, WantsToUseItem>,
|
WriteStorage<'a, WantsToUseItem>,
|
||||||
ReadStorage<'a, Name>,
|
ReadStorage<'a, Name>,
|
||||||
ReadStorage<'a, Consumable>,
|
|
||||||
ReadStorage<'a, ProvidesHealing>,
|
|
||||||
ReadStorage<'a, InflictsDamage>,
|
|
||||||
WriteStorage<'a, Pools>,
|
|
||||||
WriteStorage<'a, SufferDamage>,
|
|
||||||
ReadStorage<'a, AreaOfEffect>,
|
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>,
|
WriteStorage<'a, EquipmentChanged>,
|
||||||
ReadStorage<'a, TownPortal>,
|
|
||||||
WriteStorage<'a, IdentifiedItem>,
|
WriteStorage<'a, IdentifiedItem>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -42,26 +23,12 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (
|
let (
|
||||||
player_entity,
|
player_entity,
|
||||||
mut gamelog,
|
|
||||||
map,
|
map,
|
||||||
entities,
|
entities,
|
||||||
mut wants_use,
|
mut wants_use,
|
||||||
names,
|
names,
|
||||||
consumables,
|
|
||||||
healing,
|
|
||||||
inflict_damage,
|
|
||||||
mut combat_stats,
|
|
||||||
mut suffer_damage,
|
|
||||||
aoe,
|
aoe,
|
||||||
mut confused,
|
|
||||||
mut particle_builder,
|
|
||||||
positions,
|
|
||||||
provides_food,
|
|
||||||
mut hunger_clocks,
|
|
||||||
magic_mapper,
|
|
||||||
mut runstate,
|
|
||||||
mut dirty,
|
mut dirty,
|
||||||
town_portal,
|
|
||||||
mut identified_item,
|
mut identified_item,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
@ -69,46 +36,6 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
dirty
|
dirty
|
||||||
.insert(entity, EquipmentChanged {})
|
.insert(entity, EquipmentChanged {})
|
||||||
.expect("Unable to insert equipment change");
|
.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
|
// Identify
|
||||||
if entity == *player_entity {
|
if entity == *player_entity {
|
||||||
@ -122,173 +49,27 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
.expect("Unable to identify item");
|
.expect("Unable to identify item");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it is edible, eat it!
|
// Call the effects system
|
||||||
match provides_food.get(useitem.item) {
|
add_effect(
|
||||||
None => {}
|
Some(entity),
|
||||||
Some(_) => {
|
EffectType::ItemUse { item: useitem.item },
|
||||||
used_item = true;
|
match useitem.target {
|
||||||
let target = targets[0];
|
None => Targets::Single {
|
||||||
|
target: *player_entity,
|
||||||
if let Some(hc) = hunger_clocks.get_mut(target) {
|
},
|
||||||
hc.state = HungerState::WellFed;
|
Some(target) => {
|
||||||
hc.duration = 20;
|
if let Some(aoe) = aoe.get(useitem.item) {
|
||||||
|
Targets::Tiles {
|
||||||
gamelog.append(format!(
|
tiles: aoe_tiles(&*map, target, aoe.radius),
|
||||||
"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 {
|
} else {
|
||||||
used_item = true;
|
Targets::Tile {
|
||||||
gamelog.append("You are teleported back to town!");
|
tile_idx: map.xy_idx(target.x, target.y) as i32,
|
||||||
|
|
||||||
*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
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
wants_use.clear();
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{
|
use crate::components::{AreaOfEffect, EntityMoved, EntryTrigger, Name, Position};
|
||||||
ApplyTeleport, EntityMoved, EntryTrigger, Hidden, InflictsDamage, Name, Position,
|
use crate::effects::{add_effect, aoe_tiles, EffectType, Targets};
|
||||||
SingleActivation, TeleportTo,
|
|
||||||
};
|
|
||||||
use crate::effects::{add_effect, EffectType, Targets};
|
|
||||||
use crate::game_log::GameLog;
|
use crate::game_log::GameLog;
|
||||||
use crate::particle_system::ParticleBuilder;
|
use crate::{spatial, Map};
|
||||||
use crate::{colors, spatial, Map};
|
|
||||||
|
|
||||||
pub struct TriggerSystem {}
|
pub struct TriggerSystem {}
|
||||||
|
|
||||||
@ -18,16 +14,10 @@ impl<'a> System<'a> for TriggerSystem {
|
|||||||
WriteStorage<'a, EntityMoved>,
|
WriteStorage<'a, EntityMoved>,
|
||||||
ReadStorage<'a, Position>,
|
ReadStorage<'a, Position>,
|
||||||
ReadStorage<'a, EntryTrigger>,
|
ReadStorage<'a, EntryTrigger>,
|
||||||
WriteStorage<'a, Hidden>,
|
|
||||||
ReadStorage<'a, Name>,
|
ReadStorage<'a, Name>,
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
WriteExpect<'a, GameLog>,
|
WriteExpect<'a, GameLog>,
|
||||||
ReadStorage<'a, InflictsDamage>,
|
ReadStorage<'a, AreaOfEffect>,
|
||||||
WriteExpect<'a, ParticleBuilder>,
|
|
||||||
ReadStorage<'a, SingleActivation>,
|
|
||||||
ReadStorage<'a, TeleportTo>,
|
|
||||||
WriteStorage<'a, ApplyTeleport>,
|
|
||||||
ReadExpect<'a, Entity>,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -36,20 +26,13 @@ impl<'a> System<'a> for TriggerSystem {
|
|||||||
mut entity_moved,
|
mut entity_moved,
|
||||||
position,
|
position,
|
||||||
entry_trigger,
|
entry_trigger,
|
||||||
mut hidden,
|
|
||||||
names,
|
names,
|
||||||
entities,
|
entities,
|
||||||
mut log,
|
mut log,
|
||||||
inflicts_damage,
|
area_of_effect,
|
||||||
mut particle_builder,
|
|
||||||
single_activation,
|
|
||||||
teleporters,
|
|
||||||
mut apply_teleport,
|
|
||||||
player_entity,
|
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
// Iterate the entities that moved and their final position
|
// 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() {
|
for (entity, mut _entity_moved, pos) in (&entities, &mut entity_moved, &position).join() {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
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));
|
log.append(format!("{} triggers!", &name.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The trap is no longer hidden
|
// Call the effects system
|
||||||
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(
|
add_effect(
|
||||||
None,
|
Some(entity),
|
||||||
EffectType::Damage {
|
EffectType::TriggerFire { trigger: entity_id },
|
||||||
amount: damage.damage,
|
if let Some(aoe) = area_of_effect.get(entity_id) {
|
||||||
},
|
Targets::Tiles {
|
||||||
Targets::Single { target: entity },
|
tiles: aoe_tiles(
|
||||||
)
|
&*map,
|
||||||
|
::rltk::Point::from(*pos),
|
||||||
|
aoe.radius,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Targets::Tile {
|
||||||
|
tile_idx: idx as i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// Remove all entity movement markers
|
||||||
entity_moved.clear();
|
entity_moved.clear();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user