roguelike-game/src/ai/initiative_system.rs

87 lines
2.6 KiB
Rust

use ::rltk::{DistanceAlg, Point, RandomNumberGenerator};
use ::specs::prelude::*;
use crate::components::{Attributes, Initiative, MyTurn, Pools, Position};
use crate::RunState;
pub struct InitiativeSystem {}
impl<'a> System<'a> for InitiativeSystem {
#[allow(clippy::type_complexity)]
type SystemData = (
WriteStorage<'a, Initiative>,
ReadStorage<'a, Position>,
WriteStorage<'a, MyTurn>,
Entities<'a>,
WriteExpect<'a, RandomNumberGenerator>,
ReadStorage<'a, Attributes>,
WriteExpect<'a, RunState>,
ReadExpect<'a, Entity>,
ReadExpect<'a, Point>,
ReadStorage<'a, Pools>,
);
fn run(&mut self, data: Self::SystemData) {
let (
mut initiatives,
positions,
mut turns,
entities,
mut rng,
attributes,
mut runstate,
player,
player_pos,
pools,
) = data;
if *runstate != RunState::Ticking {
return;
}
// Clear any remaining MyTurn we left by mistake
turns.clear();
// Roll initiative
for (entity, initiative, pos) in (&entities, &mut initiatives, &positions).join() {
initiative.current -= 1;
if initiative.current < 1 {
let mut myturn = true;
// Re-roll
initiative.current = 6 + rng.roll_dice(1, 6);
// Give a bonus for quickness
if let Some(attr) = attributes.get(entity) {
initiative.current -= attr.quickness.bonus;
}
// Apply pool penalty
if let Some(pools) = pools.get(entity) {
initiative.current += f32::floor(pools.total_initiative_penalty) as i32;
}
// TODO: More initiative granting boosts/penalties will go here later
// if its the player, we want to go to an AwaitingInput state
if entity == *player {
*runstate = RunState::AwaitingInput;
} else {
let distance =
DistanceAlg::Pythagoras.distance2d(*player_pos, Point::from(*pos));
if distance > 20.0 {
myturn = false;
}
}
// It's my turn
if myturn {
turns
.insert(entity, MyTurn {})
.expect("Unable to insert turn");
}
}
}
}
}