kroz-rs/src/state.rs

154 lines
5.7 KiB
Rust

use std::time::{Duration, Instant};
use crate::components::monster::damage_for_kind;
use crate::components::{Monster, Player, Position, Renderable};
use crate::map::{Map, TileType};
use crate::resources::{Clock, ShowDebugInfo, Stats};
use crate::sound::SoundSystem;
use crate::sound_effects::SoundEffects;
use crate::systems::MonsterMotion;
use crate::{constants::*, sidebar};
use bracket_lib::prelude::*;
use specs::prelude::*;
pub struct State {
ecs: World,
}
impl GameState for State {
fn tick(&mut self, ctx: &mut BTerm) {
ctx.cls();
self.handle_input(ctx);
self.run_systems();
let map = self.ecs.fetch::<Map>();
map.draw(ctx);
let positions = self.ecs.read_storage::<Position>();
let renderables = self.ecs.read_storage::<Renderable>();
for (pos, render) in (&positions, &renderables).join() {
ctx.set(
pos.x + MAP_X as i32,
pos.y + MAP_Y as i32,
render.fg,
render.bg,
render.glyph,
);
}
sidebar::draw(&self.ecs, ctx);
}
}
impl State {
pub fn new(ecs: World) -> Self {
State { ecs }
}
fn handle_input(&mut self, ctx: &mut BTerm) {
// Player movement
match ctx.key {
None => {} // Nothing happened
Some(key) => match key {
VirtualKeyCode::Left | VirtualKeyCode::J => {
self.try_move_player(-1, 0);
}
VirtualKeyCode::U | VirtualKeyCode::Home => self.try_move_player(-1, -1),
VirtualKeyCode::Up | VirtualKeyCode::I => {
self.try_move_player(0, -1);
}
VirtualKeyCode::O | VirtualKeyCode::PageUp => self.try_move_player(1, -1),
VirtualKeyCode::Right | VirtualKeyCode::K => {
self.try_move_player(1, 0);
}
VirtualKeyCode::Comma | VirtualKeyCode::PageDown => self.try_move_player(1, 1),
VirtualKeyCode::Down | VirtualKeyCode::M => {
self.try_move_player(0, 1);
}
VirtualKeyCode::N | VirtualKeyCode::End => self.try_move_player(-1, 1),
VirtualKeyCode::S => {
let mut sound_system = self.ecs.write_resource::<SoundSystem>();
let sound_effects = self.ecs.fetch::<SoundEffects>();
sound_system.play_sound(sound_effects.pickup.clone());
}
VirtualKeyCode::D => {
let mut show_debug_info = self.ecs.write_resource::<ShowDebugInfo>();
show_debug_info.0 = !show_debug_info.0;
}
VirtualKeyCode::Escape => {
ctx.quit();
}
_ => {
let mut sound_system = self.ecs.write_resource::<SoundSystem>();
let sound_effects = self.ecs.fetch::<SoundEffects>();
sound_system.play_sound(sound_effects.bad_key.clone());
}
},
}
}
fn try_move_player(&mut self, delta_x: i32, delta_y: i32) {
let entities = self.ecs.entities();
let mut positions = self.ecs.write_storage::<Position>();
let mut players = self.ecs.write_storage::<Player>();
let mut map = self.ecs.write_resource::<Map>();
let mut stats = self.ecs.write_resource::<Stats>();
let mut sound_system = self.ecs.write_resource::<SoundSystem>();
for (player, pos) in (&mut players, &mut positions).join() {
let now = Instant::now();
if now - player.last_moved > Duration::from_secs_f32(PLAYER_STEP_PERIOD) {
let destination = Point {
x: pos.x + delta_x,
y: pos.y + delta_y,
};
let mut sound_effects = self.ecs.fetch_mut::<SoundEffects>();
if map.in_bounds(destination) {
if map.is_solid(destination) {
sound_system.play_sound(sound_effects.blocked.clone());
} else {
if let TileType::Monster(monster) = map.get_tile_at(destination) {
if let Some(monster_component) =
self.ecs.read_component::<Monster>().get(monster)
{
if stats.gems > 0 {
stats.gems -= damage_for_kind(monster_component.kind);
}
let _ = entities.delete(monster);
}
}
map.set_tile_at(Point { x: pos.x, y: pos.y }, TileType::Floor);
map.set_tile_at(destination, TileType::Player);
pos.x = destination.x;
pos.y = destination.y;
let mut player_pos = self.ecs.write_resource::<Point>();
player_pos.x = pos.x;
player_pos.y = pos.y;
self.ecs.write_resource::<Clock>().force_tick();
sound_system.play_sound(sound_effects.step.clone());
}
} else {
let static_sound = sound_effects.get_new_static_effect(&sound_system);
sound_system.play_sound(static_sound);
}
player.last_moved = now;
}
}
}
fn run_systems(&mut self) {
let mut mm = MonsterMotion {};
mm.run_now(&self.ecs);
self.ecs.maintain();
self.ecs.write_resource::<Clock>().try_tick();
}
}