particle effect on items/traps
This commit is contained in:
parent
397aa07d60
commit
f325d39f4c
7 changed files with 144 additions and 7 deletions
|
|
@ -46,7 +46,7 @@
|
||||||
"weight": 0.5,
|
"weight": 0.5,
|
||||||
"value": 50,
|
"value": 50,
|
||||||
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
||||||
"effects": { "ranged": "12", "damage": "3d4+3" },
|
"effects": { "particle_line": "*;#00b7ff;75.0;#f4fc83;100.0", "ranged": "12", "damage": "3d4+3" },
|
||||||
"magic": { "class": "uncommon", "naming": "scroll" }
|
"magic": { "class": "uncommon", "naming": "scroll" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
"weight": 0.5,
|
"weight": 0.5,
|
||||||
"value": 100,
|
"value": 100,
|
||||||
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
||||||
"effects": { "ranged": "10", "damage": "4d6", "aoe": "2" },
|
"effects": { "particle": "*;#FFA500;200.0", "ranged": "10", "damage": "4d6", "aoe": "2" },
|
||||||
"magic": { "class": "uncommon", "naming": "scroll" }
|
"magic": { "class": "uncommon", "naming": "scroll" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -410,6 +410,22 @@ pub struct Charges {
|
||||||
pub max_uses: i32,
|
pub max_uses: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct SpawnParticleLine {
|
||||||
|
pub glyph: rltk::FontCharType,
|
||||||
|
pub colour: RGB,
|
||||||
|
pub lifetime_ms: f32,
|
||||||
|
pub trail_colour: RGB,
|
||||||
|
pub trail_lifetime_ms: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct SpawnParticleBurst {
|
||||||
|
pub glyph: rltk::FontCharType,
|
||||||
|
pub colour: RGB,
|
||||||
|
pub lifetime_ms: f32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Destructible {}
|
pub struct Destructible {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{Map, Position};
|
use crate::{Equipped, InBackpack, Map, Position};
|
||||||
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
pub fn entity_position(ecs: &World, target: Entity) -> Option<usize> {
|
pub fn entity_position(ecs: &World, target: Entity) -> Option<usize> {
|
||||||
|
|
@ -18,3 +19,27 @@ pub fn aoe_tiles(map: &Map, target: rltk::Point, radius: i32) -> Vec<usize> {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_item_position(ecs: &World, target: Entity) -> Option<i32> {
|
||||||
|
let positions = ecs.read_storage::<Position>();
|
||||||
|
let map = ecs.fetch::<Map>();
|
||||||
|
// Does it have a position?
|
||||||
|
if let Some(pos) = positions.get(target) {
|
||||||
|
return Some(map.xy_idx(pos.x, pos.y) as i32);
|
||||||
|
}
|
||||||
|
// If not, is it 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Is it equipped?
|
||||||
|
if let Some(carried) = ecs.read_storage::<Equipped>().get(target) {
|
||||||
|
if let Some(pos) = positions.get(carried.owner) {
|
||||||
|
return Some(map.xy_idx(pos.x, pos.y) as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Out of luck: give up
|
||||||
|
console::log("DEBUGINFO: Failed to find item position");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use super::{add_effect, get_noncursed, spatial, EffectType, Entity, Targets, World};
|
use super::{add_effect, get_noncursed, spatial, targeting, EffectType, Entity, Targets, World};
|
||||||
use crate::{
|
use crate::{
|
||||||
gamelog, gui::item_colour_ecs, gui::obfuscate_name_ecs, gui::renderable_colour, Beatitude, Charges, Confusion,
|
gamelog, gui::item_colour_ecs, gui::obfuscate_name_ecs, gui::renderable_colour, Beatitude, Charges, Confusion,
|
||||||
Consumable, Destructible, Hidden, InflictsDamage, Item, MagicMapper, Player, Prop, ProvidesHealing,
|
Consumable, Destructible, Hidden, InflictsDamage, Item, MagicMapper, Map, Player, Prop, ProvidesHealing,
|
||||||
ProvidesNutrition, RandomNumberGenerator, Renderable, RunState, SingleActivation, BUC,
|
ProvidesNutrition, RandomNumberGenerator, Renderable, RunState, SingleActivation, SpawnParticleBurst,
|
||||||
|
SpawnParticleLine, BUC,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
pub fn item_trigger(source: Option<Entity>, item: Entity, target: &Targets, ecs: &mut World) {
|
pub fn item_trigger(source: Option<Entity>, item: Entity, target: &Targets, ecs: &mut World) {
|
||||||
// Check if the item has charges, etc.
|
// Check if the item has charges, etc.
|
||||||
if let Some(has_charges) = ecs.write_storage::<Charges>().get_mut(item) {
|
if let Some(has_charges) = ecs.write_storage::<Charges>().get_mut(item) {
|
||||||
|
|
@ -62,6 +62,41 @@ fn event_trigger(source: Option<Entity>, entity: Entity, target: &Targets, ecs:
|
||||||
let logger = gamelog::Logger::new();
|
let logger = gamelog::Logger::new();
|
||||||
|
|
||||||
let mut did_something = false;
|
let mut did_something = false;
|
||||||
|
// Simple particle spawn
|
||||||
|
if let Some(part) = ecs.read_storage::<SpawnParticleBurst>().get(entity) {
|
||||||
|
add_effect(
|
||||||
|
event.source,
|
||||||
|
EffectType::Particle {
|
||||||
|
glyph: part.glyph,
|
||||||
|
fg: part.colour,
|
||||||
|
bg: RGB::named(BLACK),
|
||||||
|
lifespan: part.lifetime_ms,
|
||||||
|
delay: 0.0,
|
||||||
|
},
|
||||||
|
event.target.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 target {
|
||||||
|
Targets::Tile { target } => spawn_line_particles(ecs, start_pos, *target as i32, part),
|
||||||
|
Targets::TileList { targets } => {
|
||||||
|
targets.iter().for_each(|target| spawn_line_particles(ecs, start_pos, *target as i32, part))
|
||||||
|
}
|
||||||
|
Targets::Entity { target } => {
|
||||||
|
if let Some(end_pos) = targeting::entity_position(ecs, *target) {
|
||||||
|
spawn_line_particles(ecs, start_pos, end_pos as i32, part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Targets::EntityList { targets } => targets.iter().for_each(|target| {
|
||||||
|
if let Some(end_pos) = targeting::entity_position(ecs, *target) {
|
||||||
|
spawn_line_particles(ecs, start_pos, end_pos as i32, part);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let (logger, restored_nutrition) = handle_restore_nutrition(ecs, &mut event, logger);
|
let (logger, restored_nutrition) = handle_restore_nutrition(ecs, &mut event, logger);
|
||||||
let (logger, magic_mapped) = handle_magic_mapper(ecs, &mut event, logger);
|
let (logger, magic_mapped) = handle_magic_mapper(ecs, &mut event, logger);
|
||||||
let (logger, healed) = handle_healing(ecs, &mut event, logger);
|
let (logger, healed) = handle_healing(ecs, &mut event, logger);
|
||||||
|
|
@ -227,3 +262,36 @@ fn get_entity_targets(target: &Targets) -> Vec<Entity> {
|
||||||
}
|
}
|
||||||
return entities;
|
return entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn spawn_line_particles(ecs: &World, start: i32, end: i32, part: &SpawnParticleLine) {
|
||||||
|
let map = ecs.fetch::<Map>();
|
||||||
|
let start_pt = Point::new(start % map.width, start / map.width);
|
||||||
|
let end_pt = Point::new(end % map.width, end / map.width);
|
||||||
|
let line = line2d(LineAlg::Bresenham, start_pt, end_pt);
|
||||||
|
for (i, pt) in line.iter().enumerate() {
|
||||||
|
add_effect(
|
||||||
|
None,
|
||||||
|
EffectType::Particle {
|
||||||
|
glyph: part.glyph,
|
||||||
|
fg: part.colour,
|
||||||
|
bg: RGB::named(BLACK),
|
||||||
|
lifespan: part.lifetime_ms,
|
||||||
|
delay: i as f32 * part.lifetime_ms,
|
||||||
|
},
|
||||||
|
Targets::Tile { target: map.xy_idx(pt.x, pt.y) },
|
||||||
|
);
|
||||||
|
if i > 0 {
|
||||||
|
add_effect(
|
||||||
|
None,
|
||||||
|
EffectType::Particle {
|
||||||
|
glyph: to_cp437('-'),
|
||||||
|
fg: part.trail_colour,
|
||||||
|
bg: RGB::named(BLACK),
|
||||||
|
lifespan: part.trail_lifetime_ms,
|
||||||
|
delay: i as f32 * part.lifetime_ms,
|
||||||
|
},
|
||||||
|
Targets::Tile { target: map.xy_idx(line[i - 1].x, line[i - 1].y) },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -610,6 +610,8 @@ fn main() -> rltk::BError {
|
||||||
gs.ecs.register::<EntityMoved>();
|
gs.ecs.register::<EntityMoved>();
|
||||||
gs.ecs.register::<MultiAttack>();
|
gs.ecs.register::<MultiAttack>();
|
||||||
gs.ecs.register::<ParticleLifetime>();
|
gs.ecs.register::<ParticleLifetime>();
|
||||||
|
gs.ecs.register::<SpawnParticleBurst>();
|
||||||
|
gs.ecs.register::<SpawnParticleLine>();
|
||||||
gs.ecs.register::<SimpleMarker<SerializeMe>>();
|
gs.ecs.register::<SimpleMarker<SerializeMe>>();
|
||||||
gs.ecs.register::<SerializationHelper>();
|
gs.ecs.register::<SerializationHelper>();
|
||||||
gs.ecs.register::<DMSerializationHelper>();
|
gs.ecs.register::<DMSerializationHelper>();
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ macro_rules! apply_effects {
|
||||||
"ac" => $eb = $eb.with(ArmourClassBonus { amount: effect.1.parse::<i32>().unwrap() }),
|
"ac" => $eb = $eb.with(ArmourClassBonus { amount: effect.1.parse::<i32>().unwrap() }),
|
||||||
"magicmapper" => $eb = $eb.with(MagicMapper {}),
|
"magicmapper" => $eb = $eb.with(MagicMapper {}),
|
||||||
"digger" => $eb = $eb.with(Digger {}),
|
"digger" => $eb = $eb.with(Digger {}),
|
||||||
|
"particle_line" => $eb = $eb.with(parse_particle_line(&effect.1)),
|
||||||
|
"particle" => $eb = $eb.with(parse_particle(&effect.1)),
|
||||||
_ => console::log(format!("Warning: effect {} not implemented.", effect_name)),
|
_ => console::log(format!("Warning: effect {} not implemented.", effect_name)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -875,3 +877,23 @@ fn get_ancestry_string(ancestry: Ancestry) -> &'static str {
|
||||||
Ancestry::NULL => return "NULL",
|
Ancestry::NULL => return "NULL",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_particle_line(n: &str) -> SpawnParticleLine {
|
||||||
|
let tokens: Vec<_> = n.split(';').collect();
|
||||||
|
SpawnParticleLine {
|
||||||
|
glyph: to_cp437(tokens[0].chars().next().unwrap()),
|
||||||
|
colour: RGB::from_hex(tokens[1]).expect("Invalid RGB"),
|
||||||
|
lifetime_ms: tokens[2].parse::<f32>().unwrap(),
|
||||||
|
trail_colour: RGB::from_hex(tokens[3]).expect("Invalid trail RGB"),
|
||||||
|
trail_lifetime_ms: tokens[4].parse::<f32>().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_particle(n: &str) -> SpawnParticleBurst {
|
||||||
|
let tokens: Vec<_> = n.split(';').collect();
|
||||||
|
SpawnParticleBurst {
|
||||||
|
glyph: to_cp437(tokens[0].chars().next().unwrap()),
|
||||||
|
colour: RGB::from_hex(tokens[1]).expect("Invalid RGB"),
|
||||||
|
lifetime_ms: tokens[2].parse::<f32>().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,8 @@ pub fn save_game(ecs: &mut World) {
|
||||||
Renderable,
|
Renderable,
|
||||||
SingleActivation,
|
SingleActivation,
|
||||||
Skills,
|
Skills,
|
||||||
|
SpawnParticleBurst,
|
||||||
|
SpawnParticleLine,
|
||||||
TakingTurn,
|
TakingTurn,
|
||||||
Telepath,
|
Telepath,
|
||||||
Viewshed,
|
Viewshed,
|
||||||
|
|
@ -222,6 +224,8 @@ pub fn load_game(ecs: &mut World) {
|
||||||
Renderable,
|
Renderable,
|
||||||
SingleActivation,
|
SingleActivation,
|
||||||
Skills,
|
Skills,
|
||||||
|
SpawnParticleBurst,
|
||||||
|
SpawnParticleLine,
|
||||||
TakingTurn,
|
TakingTurn,
|
||||||
Telepath,
|
Telepath,
|
||||||
Viewshed,
|
Viewshed,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue