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 animal_ai_system;
|
||||||
mod bystander_ai_system;
|
mod bystander_ai_system;
|
||||||
|
mod initiative_system;
|
||||||
mod monster_ai_system;
|
mod monster_ai_system;
|
||||||
|
|
||||||
pub use animal_ai_system::AnimalAI;
|
pub use animal_ai_system::AnimalAI;
|
||||||
pub use bystander_ai_system::BystanderAI;
|
pub use bystander_ai_system::BystanderAI;
|
||||||
|
pub use initiative_system::InitiativeSystem;
|
||||||
pub use monster_ai_system::MonsterAI;
|
pub use monster_ai_system::MonsterAI;
|
||||||
|
@ -2,7 +2,7 @@ use ::rltk::{DijkstraMap, DistanceAlg, Point};
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{
|
use crate::components::{
|
||||||
Carnivore, EntityMoved, Herbivore, Item, Position, Viewshed, WantsToMelee,
|
Carnivore, EntityMoved, Herbivore, Item, MyTurn, Position, Viewshed, WantsToMelee,
|
||||||
};
|
};
|
||||||
use crate::{Map, RunState};
|
use crate::{Map, RunState};
|
||||||
|
|
||||||
@ -22,6 +22,7 @@ impl<'a> System<'a> for AnimalAI {
|
|||||||
WriteStorage<'a, WantsToMelee>,
|
WriteStorage<'a, WantsToMelee>,
|
||||||
WriteStorage<'a, EntityMoved>,
|
WriteStorage<'a, EntityMoved>,
|
||||||
WriteStorage<'a, Position>,
|
WriteStorage<'a, Position>,
|
||||||
|
ReadStorage<'a, MyTurn>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -37,15 +38,12 @@ impl<'a> System<'a> for AnimalAI {
|
|||||||
mut wants_to_melee,
|
mut wants_to_melee,
|
||||||
mut entity_moved,
|
mut entity_moved,
|
||||||
mut position,
|
mut position,
|
||||||
|
turns,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
if *runstate != RunState::MonsterTurn {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Herbivores run away a lot
|
// Herbivores run away a lot
|
||||||
for (entity, mut viewshed, _herbivore, mut pos) in
|
for (entity, mut viewshed, _herbivore, mut pos, _turn) in
|
||||||
(&entities, &mut viewshed, &herbivore, &mut position).join()
|
(&entities, &mut viewshed, &herbivore, &mut position, &turns).join()
|
||||||
{
|
{
|
||||||
let mut run_away_from: Vec<usize> = Vec::new();
|
let mut run_away_from: Vec<usize> = Vec::new();
|
||||||
for other_tile in viewshed.visible_tiles.iter() {
|
for other_tile in viewshed.visible_tiles.iter() {
|
||||||
@ -85,8 +83,8 @@ impl<'a> System<'a> for AnimalAI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Carnivores just want to eat everything
|
// Carnivores just want to eat everything
|
||||||
for (entity, mut viewshed, _carnivore, mut pos) in
|
for (entity, mut viewshed, _carnivore, mut pos, _turn) in
|
||||||
(&entities, &mut viewshed, &carnivore, &mut position).join()
|
(&entities, &mut viewshed, &carnivore, &mut position, &turns).join()
|
||||||
{
|
{
|
||||||
let mut run_towards: Vec<usize> = Vec::new();
|
let mut run_towards: Vec<usize> = Vec::new();
|
||||||
let mut attacked = false;
|
let mut attacked = false;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use ::rltk::{Point, RandomNumberGenerator};
|
use ::rltk::{Point, RandomNumberGenerator};
|
||||||
use specs::prelude::*;
|
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::game_log::GameLog;
|
||||||
use crate::{Map, RunState};
|
use crate::{Map, RunState};
|
||||||
|
|
||||||
@ -22,6 +22,7 @@ impl<'a> System<'a> for BystanderAI {
|
|||||||
WriteExpect<'a, GameLog>,
|
WriteExpect<'a, GameLog>,
|
||||||
WriteStorage<'a, Quips>,
|
WriteStorage<'a, Quips>,
|
||||||
ReadStorage<'a, Name>,
|
ReadStorage<'a, Name>,
|
||||||
|
ReadStorage<'a, MyTurn>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -38,14 +39,11 @@ impl<'a> System<'a> for BystanderAI {
|
|||||||
mut gamelog,
|
mut gamelog,
|
||||||
mut quips,
|
mut quips,
|
||||||
names,
|
names,
|
||||||
|
turns,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
if *runstate != RunState::MonsterTurn {
|
for (entity, mut viewshed, _bystander, mut pos, _turn) in
|
||||||
return;
|
(&entities, &mut viewshed, &bystander, &mut position, &turns).join()
|
||||||
}
|
|
||||||
|
|
||||||
for (entity, mut viewshed, _bystander, mut pos) in
|
|
||||||
(&entities, &mut viewshed, &bystander, &mut position).join()
|
|
||||||
{
|
{
|
||||||
// Possibly quip
|
// Possibly quip
|
||||||
if let Some(quip) = quips.get_mut(entity) {
|
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 ::rltk::{Point, RGB};
|
||||||
use ::specs::prelude::*;
|
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::particle_system::ParticleBuilder;
|
||||||
use crate::{EntityMoved, Map, RunState};
|
use crate::{EntityMoved, Map, RunState};
|
||||||
|
|
||||||
@ -22,6 +22,7 @@ impl<'a> System<'a> for MonsterAI {
|
|||||||
WriteStorage<'a, Confusion>,
|
WriteStorage<'a, Confusion>,
|
||||||
WriteExpect<'a, ParticleBuilder>,
|
WriteExpect<'a, ParticleBuilder>,
|
||||||
WriteStorage<'a, EntityMoved>,
|
WriteStorage<'a, EntityMoved>,
|
||||||
|
ReadStorage<'a, MyTurn>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -38,14 +39,11 @@ impl<'a> System<'a> for MonsterAI {
|
|||||||
mut confused,
|
mut confused,
|
||||||
mut particle_builder,
|
mut particle_builder,
|
||||||
mut entity_moved,
|
mut entity_moved,
|
||||||
|
turns,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
if *runstate != RunState::MonsterTurn {
|
for (entity, mut viewshed, _monster, mut pos, _turn) in
|
||||||
return;
|
(&entities, &mut viewshed, &monster, &mut position, &turns).join()
|
||||||
}
|
|
||||||
|
|
||||||
for (entity, mut viewshed, _monster, mut pos) in
|
|
||||||
(&entities, &mut viewshed, &monster, &mut position).join()
|
|
||||||
{
|
{
|
||||||
let mut can_act = true;
|
let mut can_act = true;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{HungerClock, HungerState, SufferDamage};
|
use crate::components::{HungerClock, HungerState, MyTurn, SufferDamage};
|
||||||
use crate::game_log::GameLog;
|
use crate::game_log::GameLog;
|
||||||
use crate::RunState;
|
use crate::RunState;
|
||||||
|
|
||||||
@ -15,30 +15,21 @@ impl<'a> System<'a> for HungerSystem {
|
|||||||
ReadExpect<'a, RunState>,
|
ReadExpect<'a, RunState>,
|
||||||
WriteStorage<'a, SufferDamage>,
|
WriteStorage<'a, SufferDamage>,
|
||||||
WriteExpect<'a, GameLog>,
|
WriteExpect<'a, GameLog>,
|
||||||
|
ReadStorage<'a, MyTurn>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (entities, mut hunger_clock, player_entity, runstate, mut inflict_damage, mut log) =
|
let (
|
||||||
data;
|
entities,
|
||||||
|
mut hunger_clock,
|
||||||
|
player_entity,
|
||||||
|
runstate,
|
||||||
|
mut inflict_damage,
|
||||||
|
mut log,
|
||||||
|
turns,
|
||||||
|
) = data;
|
||||||
|
|
||||||
for (entity, mut clock) in (&entities, &mut hunger_clock).join() {
|
for (entity, mut clock, _myturn) in (&entities, &mut hunger_clock, &turns).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 {
|
|
||||||
clock.duration -= 1;
|
clock.duration -= 1;
|
||||||
|
|
||||||
if clock.duration < 1 {
|
if clock.duration < 1 {
|
||||||
@ -80,4 +71,3 @@ 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 {
|
pub enum RunState {
|
||||||
AwaitingInput,
|
AwaitingInput,
|
||||||
PreRun,
|
PreRun,
|
||||||
PlayerTurn,
|
Ticking,
|
||||||
MonsterTurn,
|
|
||||||
ShowInventory,
|
ShowInventory,
|
||||||
ShowDropItem,
|
ShowDropItem,
|
||||||
ShowTargeting {
|
ShowTargeting {
|
||||||
@ -107,15 +106,18 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_systems(&mut self) {
|
fn run_systems(&mut self) {
|
||||||
|
let mut mapindex = MapIndexingSystem {};
|
||||||
|
mapindex.run_now(&self.ecs);
|
||||||
|
|
||||||
let mut vis = VisibilitySystem {};
|
let mut vis = VisibilitySystem {};
|
||||||
vis.run_now(&self.ecs);
|
vis.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut initiative = ai::InitiativeSystem {};
|
||||||
|
initiative.run_now(&self.ecs);
|
||||||
|
|
||||||
let mut mob = ai::MonsterAI {};
|
let mut mob = ai::MonsterAI {};
|
||||||
mob.run_now(&self.ecs);
|
mob.run_now(&self.ecs);
|
||||||
|
|
||||||
let mut mapindex = MapIndexingSystem {};
|
|
||||||
mapindex.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut animal = ai::AnimalAI {};
|
let mut animal = ai::AnimalAI {};
|
||||||
animal.run_now(&self.ecs);
|
animal.run_now(&self.ecs);
|
||||||
|
|
||||||
@ -203,21 +205,15 @@ impl GameState for State {
|
|||||||
RunState::AwaitingInput => {
|
RunState::AwaitingInput => {
|
||||||
newrunstate = player_input(self, ctx);
|
newrunstate = player_input(self, ctx);
|
||||||
}
|
}
|
||||||
RunState::PlayerTurn => {
|
RunState::Ticking => {
|
||||||
self.run_systems();
|
self.run_systems();
|
||||||
self.ecs.maintain();
|
self.ecs.maintain();
|
||||||
|
|
||||||
match *self.ecs.fetch::<RunState>() {
|
newrunstate = match *self.ecs.fetch::<RunState>() {
|
||||||
RunState::MagicMapReveal { .. } => {
|
RunState::AwaitingInput => RunState::AwaitingInput,
|
||||||
newrunstate = RunState::MagicMapReveal { row: 0 }
|
RunState::MagicMapReveal { .. } => RunState::MagicMapReveal { row: 0 },
|
||||||
}
|
_ => RunState::Ticking,
|
||||||
_ => newrunstate = RunState::MonsterTurn,
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
RunState::MonsterTurn => {
|
|
||||||
self.run_systems();
|
|
||||||
self.ecs.maintain();
|
|
||||||
newrunstate = RunState::AwaitingInput;
|
|
||||||
}
|
}
|
||||||
RunState::ShowInventory => {
|
RunState::ShowInventory => {
|
||||||
let result = gui::show_inventory(self, ctx);
|
let result = gui::show_inventory(self, ctx);
|
||||||
@ -245,7 +241,7 @@ impl GameState for State {
|
|||||||
)
|
)
|
||||||
.expect("failed to add intent to use item");
|
.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");
|
.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");
|
.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");
|
.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 {
|
if row == map.height - 1 {
|
||||||
newrunstate = RunState::MonsterTurn;
|
newrunstate = RunState::Ticking;
|
||||||
} else {
|
} else {
|
||||||
newrunstate = RunState::MagicMapReveal { row: row + 1 };
|
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>();
|
let mut ppos = ecs.write_resource::<Point>();
|
||||||
ppos.x = pos.x;
|
ppos.x = pos.x;
|
||||||
ppos.y = pos.y;
|
ppos.y = pos.y;
|
||||||
result = RunState::PlayerTurn;
|
result = RunState::Ticking;
|
||||||
} else if combat_stats.get(*potential_target).is_some() {
|
} else if combat_stats.get(*potential_target).is_some() {
|
||||||
wants_to_melee
|
wants_to_melee
|
||||||
.insert(
|
.insert(
|
||||||
@ -70,7 +70,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
|||||||
)
|
)
|
||||||
.expect("Add target failed");
|
.expect("Add target failed");
|
||||||
|
|
||||||
return RunState::PlayerTurn;
|
return RunState::Ticking;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(door) = doors.get_mut(*potential_target) {
|
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] {
|
result = match map.tiles[destination_idx] {
|
||||||
TileType::DownStairs => RunState::NextLevel,
|
TileType::DownStairs => RunState::NextLevel,
|
||||||
TileType::UpStairs => RunState::PreviousLevel,
|
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);
|
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 {
|
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.");
|
.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 {
|
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