Complete Section 5.21

This commit is contained in:
Timothy Warren 2022-01-20 19:41:16 -05:00
parent 1cbb70f294
commit 03a90aba44
4 changed files with 113 additions and 3 deletions

View File

@ -47,7 +47,7 @@ pub fn death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
let mut pools = ecs.write_storage::<Pools>(); let mut pools = ecs.write_storage::<Pools>();
let attributes = ecs.read_storage::<Attributes>(); let attributes = ecs.read_storage::<Attributes>();
let map = ecs.fetch_mut::<Map>(); let map = ecs.fetch::<Map>();
if let Some(pos) = entity_position(ecs, target) { if let Some(pos) = entity_position(ecs, target) {
crate::spatial::remove_entity(target, pos as usize); crate::spatial::remove_entity(target, pos as usize);

View File

@ -22,3 +22,30 @@ pub fn aoe_tiles(map: &Map, target: ::rltk::Point, radius: i32) -> Vec<i32> {
} }
result result
} }
pub fn find_item_position(ecs: &World, target: Entity) -> Option<i32> {
let positions = ecs.read_storage::<Position>();
let map = ecs.fetch::<Map>();
// Easy - it has a position
if let Some(pos) = positions.get(target) {
return Some(map.xy_idx(pos.x, pos.y) as i32);
}
// Maybe it is carried?
if let Some(carried) = ecs.read_storage::<InBackpack>().get(target) {
if let Some(pos) = positions.get(carried.owner) {
return Some(map.xy_idx(pos.x, pos.y) as i32);
}
}
// Maybe it is equipped?
if let Some(equipped) = ecs.read_storage::<Equipped>().get(target) {
if let Some(pos) = positions.get(equipped.owner) {
return Some(map.xy_idx(pos.x, pos.y) as i32);
}
}
// No idea - give up
None
}

View File

@ -3,9 +3,11 @@ use ::specs::prelude::*;
use super::{add_effect, EffectType, Targets}; use super::{add_effect, EffectType, Targets};
use crate::components::{ use crate::components::{
Confusion, Consumable, Hidden, InflictsDamage, MagicMapper, Name, ProvidesFood, Confusion, Consumable, Hidden, InflictsDamage, MagicMapper, Name, ProvidesFood,
ProvidesHealing, SingleActivation, TeleportTo, TownPortal, ProvidesHealing, SingleActivation, SpawnParticleBurst, SpawnParticleLine, TeleportTo,
TownPortal,
}; };
use crate::{GameLog, Map, RunState}; use crate::effects::{entity_position, targeting};
use crate::{colors, GameLog, Map, RunState};
pub fn item_trigger(creator: Option<Entity>, item: Entity, targets: &Targets, ecs: &mut World) { pub fn item_trigger(creator: Option<Entity>, item: Entity, targets: &Targets, ecs: &mut World) {
// Use the item via the generic system // Use the item via the generic system
@ -48,6 +50,44 @@ fn event_trigger(
let mut did_something = false; let mut did_something = false;
let mut gamelog = ecs.fetch_mut::<GameLog>(); let mut gamelog = ecs.fetch_mut::<GameLog>();
// Simple particle spawn
if let Some(part) = ecs.read_storage::<SpawnParticleBurst>().get(entity) {
add_effect(
creator,
EffectType::Particle {
glyph: part.glyph,
fg: part.color,
bg: colors::BLACK,
lifespan: part.lifetime_ms,
},
targets.clone(),
);
}
// Line particle spawn
if let Some(part) = ecs.read_storage::<SpawnParticleLine>().get(entity) {
if let Some(start_pos) = targeting::find_item_position(ecs, entity) {
match targets {
Targets::Tile { tile_idx } => spawn_line_particles(ecs, start_pos, *tile_idx, part),
Targets::Tiles { tiles } => tiles
.iter()
.for_each(|tile_idx| spawn_line_particles(ecs, start_pos, *tile_idx, part)),
Targets::Single { target } => {
if let Some(end_pos) = entity_position(ecs, *target) {
spawn_line_particles(ecs, start_pos, end_pos, part);
}
}
Targets::TargetList { targets } => {
targets.iter().for_each(|target| {
if let Some(end_pos) = entity_position(ecs, *target) {
spawn_line_particles(ecs, start_pos, end_pos, part);
}
});
}
}
}
}
// Providing food // Providing food
if ecs.read_storage::<ProvidesFood>().get(entity).is_some() { if ecs.read_storage::<ProvidesFood>().get(entity).is_some() {
add_effect(creator, EffectType::WellFed, targets.clone()); add_effect(creator, EffectType::WellFed, targets.clone());
@ -137,3 +177,26 @@ fn event_trigger(
did_something did_something
} }
fn spawn_line_particles(ecs: &World, start: i32, end: i32, part: &SpawnParticleLine) {
use ::rltk::{LineAlg, Point};
let map = ecs.fetch::<Map>();
let start_pt = Point::new(start % map.width, end / map.width);
let end_pt = Point::new(end % map.width, end / map.width);
let line = ::rltk::line2d(LineAlg::Bresenham, start_pt, end_pt);
for pt in line.iter() {
add_effect(
None,
EffectType::Particle {
glyph: part.glyph,
fg: part.color,
bg: colors::BLACK,
lifespan: part.lifetime_ms,
},
Targets::Tile {
tile_idx: map.xy_idx(pt.x, pt.y) as i32,
},
);
}
}

View File

@ -268,6 +268,24 @@ pub fn string_to_slot(slot: &str) -> EquipmentSlot {
} }
} }
fn parse_particle_line(n: &str) -> SpawnParticleLine {
let tokens: Vec<_> = n.split(';').collect();
SpawnParticleLine {
glyph: rltk::to_cp437(tokens[0].chars().next().unwrap()),
color: RGB::from_hex(tokens[1]).expect("Invalid hex rgb color"),
lifetime_ms: tokens[2].parse::<f32>().unwrap(),
}
}
fn parse_particle(n: &str) -> SpawnParticleBurst {
let tokens: Vec<_> = n.split(';').collect();
SpawnParticleBurst {
glyph: rltk::to_cp437(tokens[0].chars().next().unwrap()),
color: RGB::from_hex(tokens[1]).expect("Invalid hex rgb color"),
lifetime_ms: tokens[2].parse::<f32>().unwrap(),
}
}
macro_rules! apply_effects { macro_rules! apply_effects {
($effects:expr, $eb:expr) => { ($effects:expr, $eb:expr) => {
for effect in $effects.iter() { for effect in $effects.iter() {
@ -302,6 +320,8 @@ macro_rules! apply_effects {
"town_portal" => $eb = $eb.with(TownPortal {}), "town_portal" => $eb = $eb.with(TownPortal {}),
"food" => $eb = $eb.with(ProvidesFood {}), "food" => $eb = $eb.with(ProvidesFood {}),
"single_activation" => $eb = $eb.with(SingleActivation {}), "single_activation" => $eb = $eb.with(SingleActivation {}),
"particle_line" => $eb = $eb.with(parse_particle_line(&effect.1)),
"particle" => $eb = $eb.with(parse_particle(&effect.1)),
_ => { _ => {
::rltk::console::log(format!( ::rltk::console::log(format!(
"Warning: consumable effect {} not implemented.", "Warning: consumable effect {} not implemented.",