kroz-rs/src/systems/monster_ai_system.rs

120 lines
4.5 KiB
Rust

use crate::{
components::{
monster::{self, damage_for_kind, sound_effect_for_kind, ticks_for_kind},
Monster, Player, Position, Renderable,
},
resources::{Clock, Map, SoundEffects, SoundOutput, Stats},
tile_data::TileType,
};
use bracket_lib::{prelude::*, random::RandomNumberGenerator};
use specs::prelude::*;
pub struct MonsterAiSystem {}
#[allow(clippy::type_complexity)]
impl<'a> System<'a> for MonsterAiSystem {
type SystemData = (
Entities<'a>,
ReadExpect<'a, Clock>,
WriteExpect<'a, Map>,
WriteExpect<'a, Stats>,
ReadExpect<'a, SoundEffects>,
WriteExpect<'a, SoundOutput>,
WriteStorage<'a, Monster>,
WriteStorage<'a, Position>,
WriteStorage<'a, Renderable>,
ReadStorage<'a, Player>,
);
fn run(
&mut self,
(
entities,
clock,
mut map,
mut stats,
sound_effects,
mut sound_output,
mut monsters,
mut positions,
mut renderables,
players,
): Self::SystemData,
) {
let mut player_position = None;
for (_entity, _player, position) in (&entities, &players, &positions).join() {
player_position = Some(Point::from(*position));
}
if let Some(player_pos) = player_position {
let mut data = (&entities, &mut monsters, &mut positions, &mut renderables)
.join()
.collect::<Vec<_>>();
for (entity, monster, position, renderable) in &mut data {
if clock.has_ticked {
monster.ticks_until_move -= 1;
if monster.ticks_until_move <= 0 {
// Change glyph
let mut rng = RandomNumberGenerator::new();
if let Some(glyph) =
rng.random_slice_entry(&monster::glyphs_for_kind(monster.kind))
{
renderable.glyph = *glyph;
}
// Move monster
let (mut delta_x, mut delta_y) = (0, 0);
if player_pos.x < position.x {
delta_x = -1;
}
if player_pos.x > position.x {
delta_x = 1;
}
if player_pos.y < position.y {
delta_y = -1;
}
if player_pos.y > position.y {
delta_y = 1;
}
let destination = Point {
x: position.x + delta_x,
y: position.y + delta_y,
};
if let Some(e) = map.get_tile_content_at(destination) {
if let Some(_player) = players.get(e) {
// TODO: Sound
map.clear_tile_content_at(Point::from(**position));
stats.take_gems(damage_for_kind(monster.kind));
sound_output.play_sound(sound_effect_for_kind(
monster.kind,
&sound_effects,
));
let _ = entities.delete(*entity);
}
} else {
let tile = map.get_tile_at_mut(destination);
match tile {
TileType::Wall => {}
TileType::Block => {
// TODO: Sound
*tile = TileType::Floor;
let _ = entities.delete(*entity);
}
_ => {
map.clear_tile_content_at(Point::from(**position));
position.x = destination.x;
position.y = destination.y;
map.set_tile_content_at(destination, *entity);
}
}
}
monster.ticks_until_move = ticks_for_kind(monster.kind);
}
}
}
}
}
}