120 lines
4.5 KiB
Rust
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|