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.draw(ctx); let positions = self.ecs.read_storage::(); let renderables = self.ecs.read_storage::(); 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::(); let sound_effects = self.ecs.fetch::(); sound_system.play_sound(sound_effects.pickup.clone()); } VirtualKeyCode::D => { let mut show_debug_info = self.ecs.write_resource::(); show_debug_info.0 = !show_debug_info.0; } VirtualKeyCode::Escape => { ctx.quit(); } _ => { let mut sound_system = self.ecs.write_resource::(); let sound_effects = self.ecs.fetch::(); 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::(); let mut players = self.ecs.write_storage::(); let mut map = self.ecs.write_resource::(); let mut stats = self.ecs.write_resource::(); let mut sound_system = self.ecs.write_resource::(); 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::(); 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::().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::(); player_pos.x = pos.x; player_pos.y = pos.y; self.ecs.write_resource::().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::().try_tick(); } }