From 754118a20937ac6d7fc6a0fc25a5cbbf33e1b6bf Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Tue, 11 Jan 2022 10:30:32 -0500 Subject: [PATCH] Refactor systems to be more generic --- src/ai.rs | 4 ++ src/ai/bystander_ai_system.rs | 39 ++------------- src/ai/monster_ai_system.rs | 93 ++++++++++++----------------------- src/ai/quipping.rs | 44 +++++++++++++++++ src/ai/turn_status.rs | 45 +++++++++++++++++ src/main.rs | 8 ++- 6 files changed, 135 insertions(+), 98 deletions(-) create mode 100644 src/ai/quipping.rs create mode 100644 src/ai/turn_status.rs diff --git a/src/ai.rs b/src/ai.rs index 7a4f1b2..52deb3e 100644 --- a/src/ai.rs +++ b/src/ai.rs @@ -2,8 +2,12 @@ mod animal_ai_system; mod bystander_ai_system; mod initiative_system; mod monster_ai_system; +mod quipping; +mod turn_status; pub use animal_ai_system::AnimalAI; pub use bystander_ai_system::BystanderAI; pub use initiative_system::InitiativeSystem; pub use monster_ai_system::MonsterAI; +pub use quipping::QuipSystem; +pub use turn_status::TurnStatusSystem; diff --git a/src/ai/bystander_ai_system.rs b/src/ai/bystander_ai_system.rs index e46db05..74c50b4 100644 --- a/src/ai/bystander_ai_system.rs +++ b/src/ai/bystander_ai_system.rs @@ -1,9 +1,8 @@ -use ::rltk::{Point, RandomNumberGenerator}; +use ::rltk::RandomNumberGenerator; use specs::prelude::*; -use crate::components::{Bystander, EntityMoved, MyTurn, Name, Position, Quips, Viewshed}; -use crate::game_log::GameLog; -use crate::{Map, RunState}; +use crate::components::{Bystander, EntityMoved, MyTurn, Position, Viewshed}; +use crate::Map; pub struct BystanderAI {} @@ -11,62 +10,30 @@ impl<'a> System<'a> for BystanderAI { #[allow(clippy::type_complexity)] type SystemData = ( WriteExpect<'a, Map>, - ReadExpect<'a, RunState>, Entities<'a>, WriteStorage<'a, Viewshed>, ReadStorage<'a, Bystander>, WriteStorage<'a, Position>, WriteStorage<'a, EntityMoved>, WriteExpect<'a, RandomNumberGenerator>, - ReadExpect<'a, Point>, - WriteExpect<'a, GameLog>, - WriteStorage<'a, Quips>, - ReadStorage<'a, Name>, ReadStorage<'a, MyTurn>, ); fn run(&mut self, data: Self::SystemData) { let ( mut map, - runstate, entities, mut viewshed, bystander, mut position, mut entity_moved, mut rng, - player_pos, - mut gamelog, - mut quips, - names, turns, ) = data; 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) { - if !quip.available.is_empty() - && viewshed.visible_tiles.contains(&player_pos) - && rng.roll_dice(1, 6) == 1 - { - let name = names.get(entity); - let quip_index = if quip.available.len() == 1 { - 0 - } else { - (rng.roll_dice(1, quip.available.len() as i32) - 1) as usize - }; - - gamelog.append(format!( - "{} says \"{}\"", - name.unwrap().name, - quip.available[quip_index] - )); - quip.available.remove(quip_index); - } - } - // Try to move randomly let mut x = pos.x; let mut y = pos.y; diff --git a/src/ai/monster_ai_system.rs b/src/ai/monster_ai_system.rs index 5a8952f..2f8d07d 100644 --- a/src/ai/monster_ai_system.rs +++ b/src/ai/monster_ai_system.rs @@ -1,9 +1,8 @@ -use ::rltk::{Point, RGB}; +use ::rltk::Point; use ::specs::prelude::*; -use crate::components::{Confusion, Monster, MyTurn, Position, Viewshed, WantsToMelee}; -use crate::particle_system::ParticleBuilder; -use crate::{EntityMoved, Map, RunState}; +use crate::components::{EntityMoved, Monster, MyTurn, Position, Viewshed, WantsToMelee}; +use crate::Map; pub struct MonsterAI {} @@ -13,14 +12,11 @@ impl<'a> System<'a> for MonsterAI { WriteExpect<'a, Map>, ReadExpect<'a, Point>, ReadExpect<'a, Entity>, - ReadExpect<'a, RunState>, Entities<'a>, WriteStorage<'a, Viewshed>, ReadStorage<'a, Monster>, WriteStorage<'a, Position>, WriteStorage<'a, WantsToMelee>, - WriteStorage<'a, Confusion>, - WriteExpect<'a, ParticleBuilder>, WriteStorage<'a, EntityMoved>, ReadStorage<'a, MyTurn>, ); @@ -30,14 +26,11 @@ impl<'a> System<'a> for MonsterAI { mut map, player_pos, player_entity, - runstate, entities, mut viewshed, monster, mut position, mut wants_to_melee, - mut confused, - mut particle_builder, mut entity_moved, turns, ) = data; @@ -45,62 +38,40 @@ impl<'a> System<'a> for MonsterAI { for (entity, mut viewshed, _monster, mut pos, _turn) in (&entities, &mut viewshed, &monster, &mut position, &turns).join() { - let mut can_act = true; - - if let Some(i_am_confused) = confused.get_mut(entity) { - i_am_confused.turns -= 1; - if i_am_confused.turns < 1 { - confused.remove(entity); - } - - can_act = false; - - particle_builder.request( - pos.x, - pos.y, - RGB::named(rltk::MAGENTA), - RGB::named(rltk::BLACK), - rltk::to_cp437('?'), - 200.0, + let distance = + rltk::DistanceAlg::Pythagoras.distance2d(Point::new(pos.x, pos.y), *player_pos); + if distance < 1.5 { + // Attack goes here + wants_to_melee + .insert( + entity, + WantsToMelee { + target: *player_entity, + }, + ) + .expect("Unable to insert attack"); + } else if viewshed.visible_tiles.contains(&*player_pos) { + // The path to the player + let path = rltk::a_star_search( + map.xy_idx(pos.x, pos.y) as i32, + map.xy_idx(player_pos.x, player_pos.y) as i32, + &*map, ); - } - if can_act { - let distance = - rltk::DistanceAlg::Pythagoras.distance2d(Point::new(pos.x, pos.y), *player_pos); - if distance < 1.5 { - // Attack goes here - wants_to_melee - .insert( - entity, - WantsToMelee { - target: *player_entity, - }, - ) - .expect("Unable to insert attack"); - } else if viewshed.visible_tiles.contains(&*player_pos) { - // The path to the player - let path = rltk::a_star_search( - map.xy_idx(pos.x, pos.y) as i32, - map.xy_idx(player_pos.x, player_pos.y) as i32, - &*map, - ); + if path.success && path.steps.len() > 1 { + let mut idx = map.xy_idx(pos.x, pos.y); - if path.success && path.steps.len() > 1 { - let mut idx = map.xy_idx(pos.x, pos.y); + map.blocked[idx] = false; + pos.x = path.steps[1] as i32 % map.width; + pos.y = path.steps[1] as i32 / map.width; - map.blocked[idx] = false; - pos.x = path.steps[1] as i32 % map.width; - pos.y = path.steps[1] as i32 / map.width; + entity_moved + .insert(entity, EntityMoved {}) + .expect("Unable to add EntityMoved flag to monster"); - entity_moved - .insert(entity, EntityMoved {}) - .expect("Unable to add EntityMoved flag to monster"); - - idx = map.xy_idx(pos.x, pos.y); - map.blocked[idx] = true; - viewshed.dirty = true; - } + idx = map.xy_idx(pos.x, pos.y); + map.blocked[idx] = true; + viewshed.dirty = true; } } } diff --git a/src/ai/quipping.rs b/src/ai/quipping.rs new file mode 100644 index 0000000..1964f24 --- /dev/null +++ b/src/ai/quipping.rs @@ -0,0 +1,44 @@ +use ::rltk::{Point, RandomNumberGenerator}; +use ::specs::prelude::*; + +use crate::components::{MyTurn, Name, Quips, Viewshed}; +use crate::game_log::GameLog; + +pub struct QuipSystem {} + +impl<'a> System<'a> for QuipSystem { + #[allow(clippy::type_complexity)] + type SystemData = ( + WriteExpect<'a, GameLog>, + WriteStorage<'a, Quips>, + ReadStorage<'a, Name>, + ReadStorage<'a, MyTurn>, + ReadExpect<'a, Point>, + ReadStorage<'a, Viewshed>, + WriteExpect<'a, RandomNumberGenerator>, + ); + + fn run(&mut self, data: Self::SystemData) { + let (mut gamelog, mut quips, names, turns, player_pos, viewsheds, mut rng) = data; + + for (quip, name, viewshed, _turn) in (&mut quips, &names, &viewsheds, &turns).join() { + if !quip.available.is_empty() + && viewshed.visible_tiles.contains(&player_pos) + && rng.roll_dice(1, 6) == 1 + { + let quip_index = if quip.available.len() == 1 { + 0 + } else { + (rng.roll_dice(1, quip.available.len() as i32) - 1) as usize + }; + + gamelog.append(format!( + "{} says \"{}\"", + name.name, quip.available[quip_index] + )); + + quip.available.remove(quip_index); + } + } + } +} diff --git a/src/ai/turn_status.rs b/src/ai/turn_status.rs new file mode 100644 index 0000000..ad1c571 --- /dev/null +++ b/src/ai/turn_status.rs @@ -0,0 +1,45 @@ +use ::specs::prelude::*; + +use crate::components::{Confusion, MyTurn}; +use crate::RunState; + +pub struct TurnStatusSystem {} + +impl<'a> System<'a> for TurnStatusSystem { + #[allow(clippy::type_complexity)] + type SystemData = ( + WriteStorage<'a, MyTurn>, + WriteStorage<'a, Confusion>, + Entities<'a>, + ReadExpect<'a, RunState>, + ); + + fn run(&mut self, data: Self::SystemData) { + let (mut turns, mut confusion, entities, runstate) = data; + + if *runstate != RunState::Ticking { + return; + } + + let mut not_my_turn: Vec = Vec::new(); + let mut not_confused: Vec = Vec::new(); + + for (entity, _turn, confused) in (&entities, &mut turns, &mut confusion).join() { + confused.turns -= 1; + + if confused.turns < 1 { + not_confused.push(entity) + } else { + not_my_turn.push(entity); + } + } + + for e in not_my_turn { + turns.remove(e); + } + + for e in not_confused { + confusion.remove(e); + } + } +} diff --git a/src/main.rs b/src/main.rs index 0b175ab..efbe96b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,6 +115,12 @@ impl State { let mut initiative = ai::InitiativeSystem {}; initiative.run_now(&self.ecs); + let mut turnstatus = ai::TurnStatusSystem {}; + turnstatus.run_now(&self.ecs); + + let mut quipper = ai::QuipSystem {}; + quipper.run_now(&self.ecs); + let mut mob = ai::MonsterAI {}; mob.run_now(&self.ecs); @@ -517,5 +523,5 @@ fn main() -> ::rltk::BError { gs.generate_world_map(1, 0); - rltk::main_loop(context, gs) + ::rltk::main_loop(context, gs) }