Complete section 5.24

This commit is contained in:
Timothy Warren 2022-01-25 15:04:00 -05:00
parent 52235a571e
commit 408f9e6ab9
6 changed files with 119 additions and 14 deletions

View File

@ -1,9 +1,11 @@
use ::rltk::RandomNumberGenerator;
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::{ use crate::components::{
Chasing, Faction, MyTurn, Position, Viewshed, WantsToApproach, WantsToFlee, Chasing, Faction, MyTurn, Name, Position, SpecialAbilities, SpellTemplate, Viewshed,
WantsToApproach, WantsToCastSpell, WantsToFlee,
}; };
use crate::raws::{self, Reaction, RAWS}; use crate::raws::{self, find_spell_entity_by_name, Reaction, RAWS};
use crate::{spatial, Map}; use crate::{spatial, Map};
pub struct VisibleAI {} pub struct VisibleAI {}
@ -21,9 +23,15 @@ impl<'a> System<'a> for VisibleAI {
ReadExpect<'a, Entity>, ReadExpect<'a, Entity>,
ReadStorage<'a, Viewshed>, ReadStorage<'a, Viewshed>,
WriteStorage<'a, Chasing>, WriteStorage<'a, Chasing>,
ReadStorage<'a, SpecialAbilities>,
WriteExpect<'a, RandomNumberGenerator>,
WriteStorage<'a, WantsToCastSpell>,
ReadStorage<'a, Name>,
ReadStorage<'a, SpellTemplate>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
use ::rltk::{DistanceAlg, Point};
let ( let (
turns, turns,
factions, factions,
@ -35,6 +43,11 @@ impl<'a> System<'a> for VisibleAI {
player, player,
viewsheds, viewsheds,
mut chasing, mut chasing,
abilities,
mut rng,
mut casting,
names,
spells,
) = data; ) = data;
for (entity, _turn, my_faction, pos, viewshed) in for (entity, _turn, my_faction, pos, viewshed) in
@ -55,18 +68,56 @@ impl<'a> System<'a> for VisibleAI {
for reaction in reactions.iter() { for reaction in reactions.iter() {
match reaction.1 { match reaction.1 {
Reaction::Attack => { Reaction::Attack => {
want_approach if let Some(abilities) = abilities.get(entity) {
.insert( let range = DistanceAlg::Pythagoras.distance2d(
entity, Point::from(*pos),
WantsToApproach { Point::new(
idx: reaction.0 as i32, reaction.0 as i32 % map.width,
}, reaction.0 as i32 / map.width,
) ),
.expect("Unable to insert intent to approach"); );
chasing for ability in abilities.abilities.iter() {
.insert(entity, Chasing { target: reaction.2 }) if range >= ability.min_range
.expect("Unable to insert intent to chase"); && range <= ability.range
done = true; && rng.roll_dice(1, 100) >= (ability.chance * 100.0) as i32
{
casting
.insert(
entity,
WantsToCastSpell {
spell: find_spell_entity_by_name(
&ability.spell,
&names,
&spells,
&entities,
)
.unwrap(),
target: Some(Point::new(
reaction.0 as i32 % map.width,
reaction.0 as i32 / map.width,
)),
},
)
.expect("Unable to insert intent to cast spell");
done = true;
}
}
}
if !done {
want_approach
.insert(
entity,
WantsToApproach {
idx: reaction.0 as i32,
},
)
.expect("Unable to insert intent to approach");
chasing
.insert(entity, Chasing { target: reaction.2 })
.expect("Unable to insert intent to chase");
done = true;
}
} }
Reaction::Flee => { Reaction::Flee => {
flee.push(reaction.0); flee.push(reaction.0);

View File

@ -445,3 +445,16 @@ pub struct Slow {
pub struct DamageOverTime { pub struct DamageOverTime {
pub damage: i32, pub damage: i32,
} }
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SpecialAbility {
pub spell: String,
pub chance: f32,
pub range: f32,
pub min_range: f32,
}
#[derive(Component, Debug, Default, Serialize, Deserialize, Clone)]
pub struct SpecialAbilities {
pub abilities: Vec<SpecialAbility>,
}

View File

@ -140,6 +140,7 @@ fn init_state() -> State {
Slow, Slow,
SpawnParticleBurst, SpawnParticleBurst,
SpawnParticleLine, SpawnParticleLine,
SpecialAbilities,
SpellTemplate, SpellTemplate,
StatusEffect, StatusEffect,
TeachesSpell, TeachesSpell,

View File

@ -24,6 +24,15 @@ pub struct Mob {
pub faction: Option<String>, pub faction: Option<String>,
pub gold: Option<String>, pub gold: Option<String>,
pub vendor: Option<Vec<String>>, pub vendor: Option<Vec<String>>,
pub abilities: Option<Vec<MobAbility>>,
}
#[derive(Deserialize, Debug)]
pub struct MobAbility {
pub spell: String,
pub chance: f32,
pub range: f32,
pub min_range: f32,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]

View File

@ -647,6 +647,20 @@ pub fn spawn_named_mob(
}) })
} }
if let Some(ability_list) = &mob_template.abilities {
let mut a = SpecialAbilities::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?
@ -821,3 +835,18 @@ pub fn find_spell_entity(ecs: &World, name: &str) -> Option<Entity> {
None None
} }
pub fn find_spell_entity_by_name(
name: &str,
names: &ReadStorage<Name>,
spell_templates: &ReadStorage<SpellTemplate>,
entities: &Entities,
) -> Option<Entity> {
for (entity, sname, _template) in (entities, names, spell_templates).join() {
if name == sname.name {
return Some(entity);
}
}
None
}

View File

@ -118,6 +118,7 @@ pub fn save_game(ecs: &mut World) {
Slow, Slow,
SpawnParticleBurst, SpawnParticleBurst,
SpawnParticleLine, SpawnParticleLine,
SpecialAbilities,
SpellTemplate, SpellTemplate,
StatusEffect, StatusEffect,
TeachesSpell, TeachesSpell,
@ -248,6 +249,7 @@ pub fn load_game(ecs: &mut World) {
Skills, Skills,
SpawnParticleBurst, SpawnParticleBurst,
SpawnParticleLine, SpawnParticleLine,
SpecialAbilities,
SpellTemplate, SpellTemplate,
StatusEffect, StatusEffect,
TeachesSpell, TeachesSpell,