Complete section 5.26

This commit is contained in:
Timothy Warren 2022-01-28 13:47:16 -05:00
parent 051be94bc9
commit a40f43b839
8 changed files with 107 additions and 11 deletions

View File

@ -521,3 +521,8 @@ pub struct TileSize {
pub x: i32, pub x: i32,
pub y: i32, pub y: i32,
} }
#[derive(Component, Debug, Default, Serialize, Deserialize, Clone)]
pub struct OnDeath {
pub abilities: Vec<SpecialAbility>,
}

View File

@ -51,3 +51,6 @@ pub struct ProvidesIdentification {}
#[derive(Component, Debug, Serialize, Deserialize, Clone)] #[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Confusion {} pub struct Confusion {}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct AlwaysTargetsSelf {}

View File

@ -1,10 +1,13 @@
use ::rltk::RandomNumberGenerator; use ::rltk::RandomNumberGenerator;
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::{Equipped, InBackpack, LootTable, Name, Player, Pools, Position}; use crate::components::{
AreaOfEffect, Equipped, InBackpack, LootTable, Name, OnDeath, Player, Pools, Position,
};
use crate::effects::*;
use crate::game_log::GameLog; use crate::game_log::GameLog;
use crate::raws::{self, SpawnType, RAWS}; use crate::raws::{self, SpawnType, RAWS};
use crate::RunState; use crate::{Map, RunState};
pub fn delete_the_dead(ecs: &mut World) { pub fn delete_the_dead(ecs: &mut World) {
let mut dead: Vec<Entity> = Vec::new(); let mut dead: Vec<Entity> = Vec::new();
@ -101,6 +104,42 @@ pub fn delete_the_dead(ecs: &mut World) {
} }
} }
// Fire death events
for victim in dead.iter() {
let death_effects = ecs.read_storage::<OnDeath>();
if let Some(death_effect) = death_effects.get(*victim) {
let mut rng = ecs.fetch_mut::<RandomNumberGenerator>();
for effect in death_effect.abilities.iter() {
if rng.roll_dice(1, 100) <= (effect.chance * 100.0) as i32 {
let map = ecs.fetch::<Map>();
if let Some(pos) = ecs.read_storage::<Position>().get(*victim) {
let spell_entity =
crate::raws::find_spell_entity(ecs, &effect.spell).unwrap();
let tile_idx = map.xy_idx(pos.x, pos.y);
let target = if let Some(aoe) =
ecs.read_storage::<AreaOfEffect>().get(spell_entity)
{
Targets::Tiles {
tiles: aoe_tiles(&map, rltk::Point::new(pos.x, pos.y), aoe.radius),
}
} else {
Targets::Tile {
tile_idx: tile_idx as i32,
}
};
add_effect(
None,
EffectType::SpellUse {
spell: crate::raws::find_spell_entity(ecs, &effect.spell).unwrap(),
},
target,
);
}
}
}
}
}
for victim in dead { for victim in dead {
ecs.delete_entity(victim) ecs.delete_entity(victim)
.expect("Unable to delete the dead"); .expect("Unable to delete the dead");

View File

@ -1,15 +1,17 @@
use ::rltk::Point;
use ::specs::prelude::*; use ::specs::prelude::*;
use super::{add_effect, EffectType, Targets}; use super::{add_effect, EffectType, Targets};
use crate::components::{ use crate::components::{
AttributeBonus, Confusion, Consumable, DamageOverTime, Duration, Hidden, InflictsDamage, AlwaysTargetsSelf, AreaOfEffect, AttributeBonus, Confusion, Consumable, DamageOverTime,
MagicMapper, Name, Pools, ProvidesFood, ProvidesHealing, ProvidesIdentification, ProvidesMana, Duration, Hidden, InflictsDamage, KnownSpell, KnownSpells, MagicMapper, Name, Pools, Position,
ProvidesRemoveCurse, SingleActivation, Slow, SpawnParticleBurst, SpawnParticleLine, ProvidesFood, ProvidesHealing, ProvidesIdentification, ProvidesMana, ProvidesRemoveCurse,
SpellTemplate, TeachesSpell, TeleportTo, TownPortal, SingleActivation, Slow, SpawnParticleBurst, SpawnParticleLine, SpellTemplate, TeachesSpell,
TeleportTo, TownPortal,
}; };
use crate::effects::{entity_position, targeting}; use crate::effects::{aoe_tiles, entity_position, targeting};
use crate::raws::find_spell_entity; use crate::raws::find_spell_entity;
use crate::{colors, GameLog, KnownSpell, KnownSpells, Map, RunState}; 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) {
// Check charges // Check charges
@ -44,6 +46,8 @@ pub fn item_trigger(creator: Option<Entity>, item: Entity, targets: &Targets, ec
} }
pub fn spell_trigger(creator: Option<Entity>, spell: Entity, targets: &Targets, ecs: &mut World) { pub fn spell_trigger(creator: Option<Entity>, spell: Entity, targets: &Targets, ecs: &mut World) {
let mut targeting = targets.clone();
let mut self_destruct = false;
if let Some(template) = ecs.read_storage::<SpellTemplate>().get(spell) { if let Some(template) = ecs.read_storage::<SpellTemplate>().get(spell) {
let mut pools = ecs.write_storage::<Pools>(); let mut pools = ecs.write_storage::<Pools>();
if let Some(caster) = creator { if let Some(caster) = creator {
@ -52,10 +56,33 @@ pub fn spell_trigger(creator: Option<Entity>, spell: Entity, targets: &Targets,
pool.mana.current -= template.mana_cost; pool.mana.current -= template.mana_cost;
} }
} }
// Handle self-targeting override
if ecs.read_storage::<AlwaysTargetsSelf>().get(spell).is_some() {
if let Some(pos) = ecs.read_storage::<Position>().get(caster) {
let map = ecs.fetch::<Map>();
targeting = if let Some(aoe) = ecs.read_storage::<AreaOfEffect>().get(spell) {
Targets::Tiles {
tiles: aoe_tiles(&map, Point::new(pos.x, pos.y), aoe.radius),
}
} else {
Targets::Tile {
tile_idx: map.xy_idx(pos.x, pos.y) as i32,
}
}
}
}
}
if let Some(_destruct) = ecs.read_storage::<SingleActivation>().get(spell) {
self_destruct = true;
} }
} }
event_trigger(creator, spell, &targeting, ecs);
event_trigger(creator, spell, targets, ecs); if self_destruct && creator.is_some() {
ecs.entities()
.delete(creator.unwrap())
.expect("Unable to delete owner");
}
} }
pub fn trigger(creator: Option<Entity>, trigger: Entity, targets: &Targets, ecs: &mut World) { pub fn trigger(creator: Option<Entity>, trigger: Entity, targets: &Targets, ecs: &mut World) {
@ -320,7 +347,7 @@ fn event_trigger(
} }
fn spawn_line_particles(ecs: &World, start: i32, end: i32, part: &SpawnParticleLine) { fn spawn_line_particles(ecs: &World, start: i32, end: i32, part: &SpawnParticleLine) {
use ::rltk::{LineAlg, Point}; use ::rltk::LineAlg;
let map = ecs.fetch::<Map>(); let map = ecs.fetch::<Map>();
let start_pt = Point::new(start % map.width, end / map.width); let start_pt = Point::new(start % map.width, end / map.width);

View File

@ -81,6 +81,7 @@ fn init_state() -> State {
register!( register!(
state <- state <-
AlwaysTargetsSelf,
ApplyMove, ApplyMove,
ApplyTeleport, ApplyTeleport,
AreaOfEffect, AreaOfEffect,
@ -120,6 +121,7 @@ fn init_state() -> State {
Name, Name,
NaturalAttackDefense, NaturalAttackDefense,
ObfuscatedName, ObfuscatedName,
OnDeath,
OtherLevelPosition, OtherLevelPosition,
ParticleLifetime, ParticleLifetime,
Player, Player,

View File

@ -25,6 +25,7 @@ pub struct Mob {
pub gold: Option<String>, pub gold: Option<String>,
pub vendor: Option<Vec<String>>, pub vendor: Option<Vec<String>>,
pub abilities: Option<Vec<MobAbility>>, pub abilities: Option<Vec<MobAbility>>,
pub on_death: Option<Vec<MobAbility>>,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]

View File

@ -337,6 +337,7 @@ macro_rules! apply_effects {
damage: effect.1.parse::<i32>().unwrap(), damage: effect.1.parse::<i32>().unwrap(),
}) })
} }
"target_self" => $eb = $eb.with(AlwaysTargetsSelf {}),
_ => { _ => {
console::log(format!( console::log(format!(
"WARNING: consumable effect '{}' not implemented.", "WARNING: consumable effect '{}' not implemented.",
@ -667,6 +668,20 @@ pub fn spawn_named_mob(
eb = eb.with(a); eb = eb.with(a);
} }
if let Some(ability_list) = &mob_template.on_death {
let mut a = OnDeath::default();
for ability in ability_list.iter() {
a.abilities.push(SpecialAbility {
chance: ability.chance,
spell: ability.spell.clone(),
range: ability.range,
min_range: ability.min_range,
});
}
eb = eb.with(a);
}
let new_mob = eb.build(); let new_mob = eb.build();
// Are they wielding anything? // Are they wielding anything?

View File

@ -60,6 +60,7 @@ pub fn save_game(ecs: &mut World) {
ecs, ecs,
serializer, serializer,
data, data,
AlwaysTargetsSelf,
ApplyMove, ApplyMove,
ApplyTeleport, ApplyTeleport,
AreaOfEffect, AreaOfEffect,
@ -99,6 +100,7 @@ pub fn save_game(ecs: &mut World) {
Name, Name,
NaturalAttackDefense, NaturalAttackDefense,
ObfuscatedName, ObfuscatedName,
OnDeath,
OtherLevelPosition, OtherLevelPosition,
ParticleLifetime, ParticleLifetime,
Player, Player,
@ -192,6 +194,7 @@ pub fn load_game(ecs: &mut World) {
ecs, ecs,
de, de,
d, d,
AlwaysTargetsSelf,
ApplyMove, ApplyMove,
ApplyTeleport, ApplyTeleport,
AreaOfEffect, AreaOfEffect,
@ -231,6 +234,7 @@ pub fn load_game(ecs: &mut World) {
Name, Name,
NaturalAttackDefense, NaturalAttackDefense,
ObfuscatedName, ObfuscatedName,
OnDeath,
OtherLevelPosition, OtherLevelPosition,
ParticleLifetime, ParticleLifetime,
Player, Player,