Add initiative system, and refactor systems to use new runstate
This commit is contained in:
parent
3def036868
commit
f0ac291e6a
@ -1,7 +1,9 @@
|
||||
mod animal_ai_system;
|
||||
mod bystander_ai_system;
|
||||
mod initiative_system;
|
||||
mod monster_ai_system;
|
||||
|
||||
pub use animal_ai_system::AnimalAI;
|
||||
pub use bystander_ai_system::BystanderAI;
|
||||
pub use initiative_system::InitiativeSystem;
|
||||
pub use monster_ai_system::MonsterAI;
|
||||
|
@ -2,7 +2,7 @@ use ::rltk::{DijkstraMap, DistanceAlg, Point};
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use crate::components::{
|
||||
Carnivore, EntityMoved, Herbivore, Item, Position, Viewshed, WantsToMelee,
|
||||
Carnivore, EntityMoved, Herbivore, Item, MyTurn, Position, Viewshed, WantsToMelee,
|
||||
};
|
||||
use crate::{Map, RunState};
|
||||
|
||||
@ -22,6 +22,7 @@ impl<'a> System<'a> for AnimalAI {
|
||||
WriteStorage<'a, WantsToMelee>,
|
||||
WriteStorage<'a, EntityMoved>,
|
||||
WriteStorage<'a, Position>,
|
||||
ReadStorage<'a, MyTurn>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
@ -37,15 +38,12 @@ impl<'a> System<'a> for AnimalAI {
|
||||
mut wants_to_melee,
|
||||
mut entity_moved,
|
||||
mut position,
|
||||
turns,
|
||||
) = data;
|
||||
|
||||
if *runstate != RunState::MonsterTurn {
|
||||
return;
|
||||
}
|
||||
|
||||
// Herbivores run away a lot
|
||||
for (entity, mut viewshed, _herbivore, mut pos) in
|
||||
(&entities, &mut viewshed, &herbivore, &mut position).join()
|
||||
for (entity, mut viewshed, _herbivore, mut pos, _turn) in
|
||||
(&entities, &mut viewshed, &herbivore, &mut position, &turns).join()
|
||||
{
|
||||
let mut run_away_from: Vec<usize> = Vec::new();
|
||||
for other_tile in viewshed.visible_tiles.iter() {
|
||||
@ -85,8 +83,8 @@ impl<'a> System<'a> for AnimalAI {
|
||||
}
|
||||
|
||||
// Carnivores just want to eat everything
|
||||
for (entity, mut viewshed, _carnivore, mut pos) in
|
||||
(&entities, &mut viewshed, &carnivore, &mut position).join()
|
||||
for (entity, mut viewshed, _carnivore, mut pos, _turn) in
|
||||
(&entities, &mut viewshed, &carnivore, &mut position, &turns).join()
|
||||
{
|
||||
let mut run_towards: Vec<usize> = Vec::new();
|
||||
let mut attacked = false;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use ::rltk::{Point, RandomNumberGenerator};
|
||||
use specs::prelude::*;
|
||||
|
||||
use crate::components::{Bystander, EntityMoved, Name, Position, Quips, Viewshed};
|
||||
use crate::components::{Bystander, EntityMoved, MyTurn, Name, Position, Quips, Viewshed};
|
||||
use crate::game_log::GameLog;
|
||||
use crate::{Map, RunState};
|
||||
|
||||
@ -22,6 +22,7 @@ impl<'a> System<'a> for BystanderAI {
|
||||
WriteExpect<'a, GameLog>,
|
||||
WriteStorage<'a, Quips>,
|
||||
ReadStorage<'a, Name>,
|
||||
ReadStorage<'a, MyTurn>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
@ -38,14 +39,11 @@ impl<'a> System<'a> for BystanderAI {
|
||||
mut gamelog,
|
||||
mut quips,
|
||||
names,
|
||||
turns,
|
||||
) = data;
|
||||
|
||||
if *runstate != RunState::MonsterTurn {
|
||||
return;
|
||||
}
|
||||
|
||||
for (entity, mut viewshed, _bystander, mut pos) in
|
||||
(&entities, &mut viewshed, &bystander, &mut position).join()
|
||||
for (entity, mut viewshed, _bystander, mut pos, _turn) in
|
||||
(&entities, &mut viewshed, &bystander, &mut position, &turns).join()
|
||||
{
|
||||
// Possibly quip
|
||||
if let Some(quip) = quips.get_mut(entity) {
|
||||
|
67
src/ai/initiative_system.rs
Normal file
67
src/ai/initiative_system.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use ::rltk::RandomNumberGenerator;
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use crate::components::{Attributes, Initiative, MyTurn, 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>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
let (
|
||||
mut initiatives,
|
||||
positions,
|
||||
mut turns,
|
||||
entities,
|
||||
mut rng,
|
||||
attributes,
|
||||
mut runstate,
|
||||
player,
|
||||
) = data;
|
||||
|
||||
if *runstate != RunState::Ticking {
|
||||
return;
|
||||
} // We'll be adding Ticking in a moment
|
||||
|
||||
// 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 {
|
||||
// It's my turn
|
||||
turns
|
||||
.insert(entity, MyTurn {})
|
||||
.expect("Unable to insert turn");
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use ::rltk::{Point, RGB};
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use crate::components::{Confusion, Monster, Position, Viewshed, WantsToMelee};
|
||||
use crate::components::{Confusion, Monster, MyTurn, Position, Viewshed, WantsToMelee};
|
||||
use crate::particle_system::ParticleBuilder;
|
||||
use crate::{EntityMoved, Map, RunState};
|
||||
|
||||
@ -22,6 +22,7 @@ impl<'a> System<'a> for MonsterAI {
|
||||
WriteStorage<'a, Confusion>,
|
||||
WriteExpect<'a, ParticleBuilder>,
|
||||
WriteStorage<'a, EntityMoved>,
|
||||
ReadStorage<'a, MyTurn>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
@ -38,14 +39,11 @@ impl<'a> System<'a> for MonsterAI {
|
||||
mut confused,
|
||||
mut particle_builder,
|
||||
mut entity_moved,
|
||||
turns,
|
||||
) = data;
|
||||
|
||||
if *runstate != RunState::MonsterTurn {
|
||||
return;
|
||||
}
|
||||
|
||||
for (entity, mut viewshed, _monster, mut pos) in
|
||||
(&entities, &mut viewshed, &monster, &mut position).join()
|
||||
for (entity, mut viewshed, _monster, mut pos, _turn) in
|
||||
(&entities, &mut viewshed, &monster, &mut position, &turns).join()
|
||||
{
|
||||
let mut can_act = true;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use crate::components::{HungerClock, HungerState, SufferDamage};
|
||||
use crate::components::{HungerClock, HungerState, MyTurn, SufferDamage};
|
||||
use crate::game_log::GameLog;
|
||||
use crate::RunState;
|
||||
|
||||
@ -15,30 +15,21 @@ impl<'a> System<'a> for HungerSystem {
|
||||
ReadExpect<'a, RunState>,
|
||||
WriteStorage<'a, SufferDamage>,
|
||||
WriteExpect<'a, GameLog>,
|
||||
ReadStorage<'a, MyTurn>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
let (entities, mut hunger_clock, player_entity, runstate, mut inflict_damage, mut log) =
|
||||
data;
|
||||
let (
|
||||
entities,
|
||||
mut hunger_clock,
|
||||
player_entity,
|
||||
runstate,
|
||||
mut inflict_damage,
|
||||
mut log,
|
||||
turns,
|
||||
) = data;
|
||||
|
||||
for (entity, mut clock) in (&entities, &mut hunger_clock).join() {
|
||||
let mut proceed = false;
|
||||
|
||||
match *runstate {
|
||||
RunState::PlayerTurn => {
|
||||
if entity == *player_entity {
|
||||
proceed = true;
|
||||
}
|
||||
}
|
||||
RunState::MonsterTurn => {
|
||||
if entity != *player_entity {
|
||||
proceed = true;
|
||||
}
|
||||
}
|
||||
_ => proceed = false,
|
||||
}
|
||||
|
||||
if proceed {
|
||||
for (entity, mut clock, _myturn) in (&entities, &mut hunger_clock, &turns).join() {
|
||||
clock.duration -= 1;
|
||||
|
||||
if clock.duration < 1 {
|
||||
@ -79,5 +70,4 @@ impl<'a> System<'a> for HungerSystem {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
40
src/main.rs
40
src/main.rs
@ -62,8 +62,7 @@ const SHOW_MAPGEN_VISUALIZER: bool = false;
|
||||
pub enum RunState {
|
||||
AwaitingInput,
|
||||
PreRun,
|
||||
PlayerTurn,
|
||||
MonsterTurn,
|
||||
Ticking,
|
||||
ShowInventory,
|
||||
ShowDropItem,
|
||||
ShowTargeting {
|
||||
@ -107,15 +106,18 @@ impl State {
|
||||
}
|
||||
|
||||
fn run_systems(&mut self) {
|
||||
let mut mapindex = MapIndexingSystem {};
|
||||
mapindex.run_now(&self.ecs);
|
||||
|
||||
let mut vis = VisibilitySystem {};
|
||||
vis.run_now(&self.ecs);
|
||||
|
||||
let mut initiative = ai::InitiativeSystem {};
|
||||
initiative.run_now(&self.ecs);
|
||||
|
||||
let mut mob = ai::MonsterAI {};
|
||||
mob.run_now(&self.ecs);
|
||||
|
||||
let mut mapindex = MapIndexingSystem {};
|
||||
mapindex.run_now(&self.ecs);
|
||||
|
||||
let mut animal = ai::AnimalAI {};
|
||||
animal.run_now(&self.ecs);
|
||||
|
||||
@ -203,21 +205,15 @@ impl GameState for State {
|
||||
RunState::AwaitingInput => {
|
||||
newrunstate = player_input(self, ctx);
|
||||
}
|
||||
RunState::PlayerTurn => {
|
||||
RunState::Ticking => {
|
||||
self.run_systems();
|
||||
self.ecs.maintain();
|
||||
|
||||
match *self.ecs.fetch::<RunState>() {
|
||||
RunState::MagicMapReveal { .. } => {
|
||||
newrunstate = RunState::MagicMapReveal { row: 0 }
|
||||
}
|
||||
_ => newrunstate = RunState::MonsterTurn,
|
||||
}
|
||||
}
|
||||
RunState::MonsterTurn => {
|
||||
self.run_systems();
|
||||
self.ecs.maintain();
|
||||
newrunstate = RunState::AwaitingInput;
|
||||
newrunstate = match *self.ecs.fetch::<RunState>() {
|
||||
RunState::AwaitingInput => RunState::AwaitingInput,
|
||||
RunState::MagicMapReveal { .. } => RunState::MagicMapReveal { row: 0 },
|
||||
_ => RunState::Ticking,
|
||||
};
|
||||
}
|
||||
RunState::ShowInventory => {
|
||||
let result = gui::show_inventory(self, ctx);
|
||||
@ -245,7 +241,7 @@ impl GameState for State {
|
||||
)
|
||||
.expect("failed to add intent to use item");
|
||||
|
||||
newrunstate = RunState::PlayerTurn;
|
||||
newrunstate = RunState::Ticking;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,7 +261,7 @@ impl GameState for State {
|
||||
)
|
||||
.expect("failed to add intent to drop item");
|
||||
|
||||
newrunstate = RunState::PlayerTurn;
|
||||
newrunstate = RunState::Ticking;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -284,7 +280,7 @@ impl GameState for State {
|
||||
)
|
||||
.expect("Unable to insert intent to remove item");
|
||||
|
||||
newrunstate = RunState::PlayerTurn;
|
||||
newrunstate = RunState::Ticking;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -306,7 +302,7 @@ impl GameState for State {
|
||||
)
|
||||
.expect("failed to add intent to use item");
|
||||
|
||||
newrunstate = RunState::PlayerTurn;
|
||||
newrunstate = RunState::Ticking;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -361,7 +357,7 @@ impl GameState for State {
|
||||
}
|
||||
|
||||
if row == map.height - 1 {
|
||||
newrunstate = RunState::MonsterTurn;
|
||||
newrunstate = RunState::Ticking;
|
||||
} else {
|
||||
newrunstate = RunState::MagicMapReveal { row: row + 1 };
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
||||
let mut ppos = ecs.write_resource::<Point>();
|
||||
ppos.x = pos.x;
|
||||
ppos.y = pos.y;
|
||||
result = RunState::PlayerTurn;
|
||||
result = RunState::Ticking;
|
||||
} else if combat_stats.get(*potential_target).is_some() {
|
||||
wants_to_melee
|
||||
.insert(
|
||||
@ -70,7 +70,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
||||
)
|
||||
.expect("Add target failed");
|
||||
|
||||
return RunState::PlayerTurn;
|
||||
return RunState::Ticking;
|
||||
}
|
||||
|
||||
if let Some(door) = doors.get_mut(*potential_target) {
|
||||
@ -100,7 +100,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
||||
result = match map.tiles[destination_idx] {
|
||||
TileType::DownStairs => RunState::NextLevel,
|
||||
TileType::UpStairs => RunState::PreviousLevel,
|
||||
_ => RunState::PlayerTurn,
|
||||
_ => RunState::Ticking,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -218,7 +218,7 @@ fn skip_turn(ecs: &mut World) -> RunState {
|
||||
pools.hit_points.current = i32::min(pools.hit_points.current + 1, pools.hit_points.max);
|
||||
}
|
||||
|
||||
RunState::PlayerTurn
|
||||
RunState::Ticking
|
||||
}
|
||||
|
||||
fn use_consumable_hotkey(gs: &mut State, key: i32) -> RunState {
|
||||
@ -259,10 +259,10 @@ fn use_consumable_hotkey(gs: &mut State, key: i32) -> RunState {
|
||||
)
|
||||
.expect("Unable to insert intent to use item.");
|
||||
|
||||
return RunState::PlayerTurn;
|
||||
return RunState::Ticking;
|
||||
}
|
||||
|
||||
RunState::PlayerTurn
|
||||
RunState::Ticking
|
||||
}
|
||||
|
||||
pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
|
||||
@ -366,5 +366,5 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
|
||||
},
|
||||
}
|
||||
|
||||
RunState::PlayerTurn
|
||||
RunState::Ticking
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user