faction-based visible ai, initial commit

This commit is contained in:
Llywelwyn 2023-08-15 18:05:25 +01:00
parent bb8cf69b86
commit b95f0cc1ad
4 changed files with 115 additions and 1 deletions

View file

@ -1,5 +1,4 @@
use crate::{raws::Reaction, Faction, Map, Position, TakingTurn, WantsToMelee};
use rltk::prelude::*;
use specs::prelude::*;
pub struct AdjacentAI {}

View file

@ -14,3 +14,5 @@ mod monster_ai_system;
pub use monster_ai_system::MonsterAI;
mod adjacent_ai_system;
pub use adjacent_ai_system::AdjacentAI;
mod visible_ai_system;
pub use visible_ai_system::VisibleAI;

111
src/ai/visible_ai_system.rs Normal file
View file

@ -0,0 +1,111 @@
use crate::{
raws::Reaction, Faction, Map, Mind, Position, TakingTurn, Telepath, Viewshed, WantsToApproach, WantsToFlee,
};
use specs::prelude::*;
use std::collections::HashSet;
pub struct VisibleAI {}
impl<'a> System<'a> for VisibleAI {
#[allow(clippy::type_complexity)]
type SystemData = (
WriteStorage<'a, TakingTurn>,
ReadStorage<'a, Faction>,
ReadStorage<'a, Position>,
ReadExpect<'a, Map>,
WriteStorage<'a, WantsToApproach>,
WriteStorage<'a, WantsToFlee>,
Entities<'a>,
ReadExpect<'a, Entity>,
ReadStorage<'a, Viewshed>,
ReadStorage<'a, Telepath>,
ReadStorage<'a, Mind>,
);
fn run(&mut self, data: Self::SystemData) {
let (
mut turns,
factions,
positions,
map,
mut wants_to_approach,
mut wants_to_flee,
entities,
player,
viewsheds,
telepaths,
minds,
) = data;
for (entity, _turn, faction, pos, viewshed) in (&entities, &turns, &factions, &positions, &viewsheds).join() {
if entity == *player {
continue;
}
let this_idx = map.xy_idx(pos.x, pos.y);
let mut reactions: Vec<(usize, Reaction)> = Vec::new();
let mut flee: Vec<usize> = Vec::new();
let mut idxs: HashSet<usize> = HashSet::new();
for visible_tile in viewshed.visible_tiles.iter() {
let idx = map.xy_idx(visible_tile.x, visible_tile.y);
if this_idx != idx {
evaluate(idx, &map, &factions, &faction.name, &mut reactions, None);
idxs.insert(idx);
}
}
if let Some(is_telepath) = telepaths.get(entity) {
for telepath_tile in is_telepath.telepath_tiles.iter() {
let idx = map.xy_idx(telepath_tile.x, telepath_tile.y);
// If we didn't already evaluate this idx (if it's not contained in the HashSet),
// and it's not the idx we're standing on, then evaluate here w/ minds taken into
// account.
if this_idx != idx && idxs.contains(&idx) {
evaluate(idx, &map, &factions, &faction.name, &mut reactions, Some(&minds));
}
}
}
let mut done = false;
for reaction in reactions.iter() {
match reaction.1 {
Reaction::Attack => {
wants_to_approach
.insert(entity, WantsToApproach { idx: reaction.0 as i32 })
.expect("Error inserting WantsToApproach");
done = true;
}
Reaction::Flee => {
flee.push(reaction.0);
}
_ => {}
}
}
if !done && !flee.is_empty() {
wants_to_flee.insert(entity, WantsToFlee { indices: flee }).expect("Unable to insert");
}
}
}
}
fn evaluate(
idx: usize,
map: &Map,
factions: &ReadStorage<Faction>,
this_faction: &str,
reactions: &mut Vec<(usize, Reaction)>,
minds: Option<&ReadStorage<Mind>>,
) {
for other_entity in map.tile_content[idx].iter() {
// If minds are passed, we assume we're using telepathy here,
// so if the other entity is mindless, we skip it.
if minds.is_some() {
if minds.unwrap().get(*other_entity).is_none() {
continue;
}
}
if let Some(faction) = factions.get(*other_entity) {
reactions.push((
idx,
crate::raws::faction_reaction(this_faction, &faction.name, &crate::raws::RAWS.lock().unwrap()),
));
}
}
}

View file

@ -97,6 +97,7 @@ impl State {
let mut turn_status_system = ai::TurnStatusSystem {};
let mut quip_system = ai::QuipSystem {};
let mut adjacent_ai = ai::AdjacentAI {};
let mut visible_ai = ai::VisibleAI {};
let mut mob = ai::MonsterAI {};
let mut bystanders = ai::BystanderAI {};
let mut trigger_system = trigger_system::TriggerSystem {};
@ -118,6 +119,7 @@ impl State {
turn_status_system.run_now(&self.ecs);
quip_system.run_now(&self.ecs);
adjacent_ai.run_now(&self.ecs);
visible_ai.run_now(&self.ecs);
mob.run_now(&self.ecs);
bystanders.run_now(&self.ecs);
trigger_system.run_now(&self.ecs);