Heavily reorganize code
This commit is contained in:
parent
6ae930cb43
commit
9d911d8c72
18 changed files with 454 additions and 386 deletions
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
graphics::vga_color as vga,
|
||||||
resources::{sound_output::SoundSamples, SoundEffects},
|
resources::{sound_output::SoundSamples, SoundEffects},
|
||||||
vga_color as vga,
|
|
||||||
};
|
};
|
||||||
use bracket_lib::prelude::*;
|
use bracket_lib::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
19
src/graphics/entities.rs
Normal file
19
src/graphics/entities.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use bracket_lib::prelude::*;
|
||||||
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
use crate::{components::*, constants::*};
|
||||||
|
|
||||||
|
pub fn draw(world: &World, bterm: &mut BTerm) {
|
||||||
|
let positions = world.read_storage::<Position>();
|
||||||
|
let renderables = world.read_storage::<Renderable>();
|
||||||
|
|
||||||
|
for (pos, render) in (&positions, &renderables).join() {
|
||||||
|
bterm.set(
|
||||||
|
pos.x + MAP_X as i32,
|
||||||
|
pos.y + MAP_Y as i32,
|
||||||
|
render.fg,
|
||||||
|
render.bg,
|
||||||
|
render.glyph,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
9
src/graphics/map.rs
Normal file
9
src/graphics/map.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use bracket_lib::prelude::*;
|
||||||
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
use crate::resources::*;
|
||||||
|
|
||||||
|
pub fn draw(world: &World, bterm: &mut BTerm) {
|
||||||
|
let map = world.fetch::<Map>();
|
||||||
|
map.draw(bterm);
|
||||||
|
}
|
16
src/graphics/mod.rs
Normal file
16
src/graphics/mod.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use bracket_lib::prelude::*;
|
||||||
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
mod entities;
|
||||||
|
mod map;
|
||||||
|
mod sidebar;
|
||||||
|
pub mod vga_color;
|
||||||
|
mod whip;
|
||||||
|
|
||||||
|
pub fn draw(world: &World, bterm: &mut BTerm) {
|
||||||
|
bterm.cls();
|
||||||
|
map::draw(world, bterm);
|
||||||
|
entities::draw(world, bterm);
|
||||||
|
whip::draw(world, bterm);
|
||||||
|
sidebar::draw(world, bterm);
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::constants::{SIDEBAR_POS_X, SIDEBAR_POS_Y};
|
use crate::constants::{SIDEBAR_POS_X, SIDEBAR_POS_Y};
|
||||||
|
use crate::graphics::vga_color as vga;
|
||||||
use crate::resources::{Clock, LevelNumber, ShowDebugInfo, Stats};
|
use crate::resources::{Clock, LevelNumber, ShowDebugInfo, Stats};
|
||||||
use crate::vga_color as vga;
|
|
||||||
use bracket_lib::prelude::*;
|
use bracket_lib::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
pub fn draw(ecs: &World, ctx: &mut BTerm) {
|
pub fn draw(world: &World, bterm: &mut BTerm) {
|
||||||
// Blue background
|
// Blue background
|
||||||
ctx.fill_region(
|
bterm.fill_region(
|
||||||
Rect {
|
Rect {
|
||||||
x1: SIDEBAR_POS_X,
|
x1: SIDEBAR_POS_X,
|
||||||
x2: SIDEBAR_POS_X + 14,
|
x2: SIDEBAR_POS_X + 14,
|
||||||
|
@ -20,7 +20,7 @@ pub fn draw(ecs: &World, ctx: &mut BTerm) {
|
||||||
|
|
||||||
// Gray number boxes
|
// Gray number boxes
|
||||||
(1..17).step_by(3).for_each(|y| {
|
(1..17).step_by(3).for_each(|y| {
|
||||||
ctx.fill_region(
|
bterm.fill_region(
|
||||||
Rect {
|
Rect {
|
||||||
x1: SIDEBAR_POS_X + 3,
|
x1: SIDEBAR_POS_X + 3,
|
||||||
x2: SIDEBAR_POS_X + 10,
|
x2: SIDEBAR_POS_X + 10,
|
||||||
|
@ -34,27 +34,27 @@ pub fn draw(ecs: &World, ctx: &mut BTerm) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stats
|
// Stats
|
||||||
ctx.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y, "Score");
|
bterm.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y, "Score");
|
||||||
ctx.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y + 3, "Level");
|
bterm.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y + 3, "Level");
|
||||||
ctx.print_centered_at(
|
bterm.print_centered_at(
|
||||||
SIDEBAR_POS_X + 6,
|
SIDEBAR_POS_X + 6,
|
||||||
SIDEBAR_POS_Y + 4,
|
SIDEBAR_POS_Y + 4,
|
||||||
ecs.read_resource::<LevelNumber>().0 + 1,
|
world.read_resource::<LevelNumber>().0 + 1,
|
||||||
);
|
);
|
||||||
ctx.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y + 6, "Gems");
|
bterm.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y + 6, "Gems");
|
||||||
ctx.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y + 9, "Whips");
|
bterm.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y + 9, "Whips");
|
||||||
ctx.print(SIDEBAR_POS_X + 2, SIDEBAR_POS_Y + 12, "Teleports");
|
bterm.print(SIDEBAR_POS_X + 2, SIDEBAR_POS_Y + 12, "Teleports");
|
||||||
ctx.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y + 15, "Keys");
|
bterm.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y + 15, "Keys");
|
||||||
|
|
||||||
let stats = ecs.read_resource::<Stats>();
|
let stats = world.read_resource::<Stats>();
|
||||||
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 1, stats.score);
|
bterm.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 1, stats.score);
|
||||||
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 7, stats.gems);
|
bterm.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 7, stats.gems);
|
||||||
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 10, stats.whips);
|
bterm.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 10, stats.whips);
|
||||||
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 13, stats.teleports);
|
bterm.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 13, stats.teleports);
|
||||||
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 16, stats.keys);
|
bterm.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 16, stats.keys);
|
||||||
|
|
||||||
// Hotkey list
|
// Hotkey list
|
||||||
ctx.print_color(
|
bterm.print_color(
|
||||||
SIDEBAR_POS_X + 3,
|
SIDEBAR_POS_X + 3,
|
||||||
SIDEBAR_POS_Y + 18,
|
SIDEBAR_POS_Y + 18,
|
||||||
RGB::named(vga::CYAN_BRIGHT),
|
RGB::named(vga::CYAN_BRIGHT),
|
||||||
|
@ -62,7 +62,7 @@ pub fn draw(ecs: &World, ctx: &mut BTerm) {
|
||||||
"OPTIONS",
|
"OPTIONS",
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.fill_region(
|
bterm.fill_region(
|
||||||
Rect {
|
Rect {
|
||||||
x1: SIDEBAR_POS_X,
|
x1: SIDEBAR_POS_X,
|
||||||
x2: SIDEBAR_POS_X + 14,
|
x2: SIDEBAR_POS_X + 14,
|
||||||
|
@ -74,7 +74,7 @@ pub fn draw(ecs: &World, ctx: &mut BTerm) {
|
||||||
RGB::named(vga::BLUE),
|
RGB::named(vga::BLUE),
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.fill_region(
|
bterm.fill_region(
|
||||||
Rect {
|
Rect {
|
||||||
x1: SIDEBAR_POS_X + 3,
|
x1: SIDEBAR_POS_X + 3,
|
||||||
x2: SIDEBAR_POS_X + 4,
|
x2: SIDEBAR_POS_X + 4,
|
||||||
|
@ -86,28 +86,28 @@ pub fn draw(ecs: &World, ctx: &mut BTerm) {
|
||||||
RGB::named(vga::BLUE),
|
RGB::named(vga::BLUE),
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 19, "Whip");
|
bterm.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 19, "Whip");
|
||||||
ctx.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 20, "Teleport");
|
bterm.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 20, "Teleport");
|
||||||
ctx.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 21, "Pause");
|
bterm.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 21, "Pause");
|
||||||
ctx.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 22, "Quit");
|
bterm.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 22, "Quit");
|
||||||
ctx.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 23, "Save");
|
bterm.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 23, "Save");
|
||||||
ctx.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 24, "Restore");
|
bterm.print(SIDEBAR_POS_X + 3, SIDEBAR_POS_Y + 24, "Restore");
|
||||||
|
|
||||||
if ecs.read_resource::<ShowDebugInfo>().0 {
|
if world.read_resource::<ShowDebugInfo>().0 {
|
||||||
ctx.print_color_right(
|
bterm.print_color_right(
|
||||||
SIDEBAR_POS_X + 14,
|
SIDEBAR_POS_X + 14,
|
||||||
SIDEBAR_POS_Y,
|
SIDEBAR_POS_Y,
|
||||||
RGB::named(vga::GREEN_BRIGHT),
|
RGB::named(vga::GREEN_BRIGHT),
|
||||||
RGB::named(vga::BLACK),
|
RGB::named(vga::BLACK),
|
||||||
&format!("{}", ctx.fps),
|
&format!("{}", bterm.fps),
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.print_color(
|
bterm.print_color(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
RGB::named(vga::YELLOW_BRIGHT),
|
RGB::named(vga::YELLOW_BRIGHT),
|
||||||
RGB::named(vga::BLACK),
|
RGB::named(vga::BLACK),
|
||||||
&format!("{}", ecs.read_resource::<Clock>().ticks),
|
&format!("{}", world.read_resource::<Clock>().ticks),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
53
src/graphics/whip.rs
Normal file
53
src/graphics/whip.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
use bracket_lib::prelude::*;
|
||||||
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
use crate::{components::*, constants::*, resources::*};
|
||||||
|
|
||||||
|
use super::{vga_color as vga, vga_color::get_by_index};
|
||||||
|
|
||||||
|
pub fn draw(world: &World, bterm: &mut BTerm) {
|
||||||
|
let positions = world.read_storage::<Position>();
|
||||||
|
let wants_to_whips = world.read_storage::<WantsToWhip>();
|
||||||
|
let map = world.read_resource::<Map>();
|
||||||
|
let mut rng = RandomNumberGenerator::new();
|
||||||
|
for (position, wants_to_whip) in (&positions, &wants_to_whips).join() {
|
||||||
|
let color = RGB::named(get_by_index(rng.range(1, 16)));
|
||||||
|
let mut rendered_frame = wants_to_whip.frame;
|
||||||
|
let frame_data = loop {
|
||||||
|
let frame_data = match rendered_frame {
|
||||||
|
0 => Some((-1, -1, '\\')),
|
||||||
|
1 => Some((-1, 0, '─')),
|
||||||
|
2 => Some((-1, 1, '/')),
|
||||||
|
3 => Some((0, 1, '│')),
|
||||||
|
4 => Some((1, 1, '\\')),
|
||||||
|
5 => Some((1, 0, '─')),
|
||||||
|
6 => Some((1, -1, '/')),
|
||||||
|
7 => Some((0, -1, '│')),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(data) = frame_data {
|
||||||
|
let dest = Point {
|
||||||
|
x: position.x + data.0,
|
||||||
|
y: position.y + data.1,
|
||||||
|
};
|
||||||
|
if map.in_bounds(dest) {
|
||||||
|
break frame_data;
|
||||||
|
}
|
||||||
|
rendered_frame += 1;
|
||||||
|
if rendered_frame > 7 {
|
||||||
|
break None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(data) = frame_data {
|
||||||
|
bterm.set(
|
||||||
|
(position.x + MAP_X as i32) + data.0,
|
||||||
|
(position.y + MAP_Y as i32) + data.1,
|
||||||
|
color,
|
||||||
|
RGB::named(vga::BLACK),
|
||||||
|
to_cp437(data.2),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
50
src/input/mod.rs
Normal file
50
src/input/mod.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use bracket_lib::prelude::*;
|
||||||
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
use crate::resources::*;
|
||||||
|
|
||||||
|
mod player;
|
||||||
|
|
||||||
|
pub fn handle(world: &World, bterm: &mut BTerm) {
|
||||||
|
match bterm.key {
|
||||||
|
None => {}
|
||||||
|
Some(key) => match key {
|
||||||
|
VirtualKeyCode::Left | VirtualKeyCode::J => {
|
||||||
|
player::try_move(-1, 0, world);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::U | VirtualKeyCode::Home => player::try_move(-1, -1, world),
|
||||||
|
VirtualKeyCode::Up | VirtualKeyCode::I => {
|
||||||
|
player::try_move(0, -1, world);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::O | VirtualKeyCode::PageUp => player::try_move(1, -1, world),
|
||||||
|
VirtualKeyCode::Right | VirtualKeyCode::K => {
|
||||||
|
player::try_move(1, 0, world);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Comma | VirtualKeyCode::PageDown => player::try_move(1, 1, world),
|
||||||
|
VirtualKeyCode::Down | VirtualKeyCode::M => {
|
||||||
|
player::try_move(0, 1, world);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::N | VirtualKeyCode::End => player::try_move(-1, 1, world),
|
||||||
|
VirtualKeyCode::W => {
|
||||||
|
player::whip(world);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::S => {
|
||||||
|
let mut sound_system = world.write_resource::<SoundOutput>();
|
||||||
|
let sound_effects = world.fetch::<SoundEffects>();
|
||||||
|
sound_system.play_sound(sound_effects.pickup.clone());
|
||||||
|
}
|
||||||
|
VirtualKeyCode::D => {
|
||||||
|
let mut show_debug_info = world.write_resource::<ShowDebugInfo>();
|
||||||
|
show_debug_info.0 = !show_debug_info.0;
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Escape | VirtualKeyCode::Q => {
|
||||||
|
bterm.quit();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut sound_system = world.write_resource::<SoundOutput>();
|
||||||
|
let sound_effects = world.fetch::<SoundEffects>();
|
||||||
|
sound_system.play_sound(sound_effects.bad_key.clone());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
95
src/input/player.rs
Normal file
95
src/input/player.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use bracket_lib::prelude::*;
|
||||||
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
components::monster::*, components::*, constants::*, resources::*, systems::TimeSystem,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn try_move(delta_x: i32, delta_y: i32, world: &World) {
|
||||||
|
let entities = world.entities();
|
||||||
|
let mut positions = world.write_storage::<Position>();
|
||||||
|
let mut players = world.write_storage::<Player>();
|
||||||
|
let monsters = world.write_storage::<Monster>();
|
||||||
|
let mut map = world.write_resource::<Map>();
|
||||||
|
let mut stats = world.write_resource::<Stats>();
|
||||||
|
let mut sound_output = world.write_resource::<SoundOutput>();
|
||||||
|
let wants_to_whips = world.read_storage::<WantsToWhip>();
|
||||||
|
let mut clock = world.write_resource::<Clock>();
|
||||||
|
|
||||||
|
for (player_entity, player, pos) in (&entities, &mut players, &mut positions).join() {
|
||||||
|
// The player shouldn't be able to move while whipping
|
||||||
|
if let Some(_wants_to_whip) = wants_to_whips.get(player_entity) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = world.fetch_mut::<SoundEffects>();
|
||||||
|
|
||||||
|
if map.in_bounds(destination) {
|
||||||
|
if map.is_solid(destination) {
|
||||||
|
sound_output.play_sound(sound_effects.blocked.clone());
|
||||||
|
} else {
|
||||||
|
if let Some(e) = map.get_tile_content_at(destination) {
|
||||||
|
if let Some(monster) = monsters.get(e) {
|
||||||
|
stats.add_score(damage_for_kind(monster.kind));
|
||||||
|
stats.take_gems(damage_for_kind(monster.kind));
|
||||||
|
sound_output
|
||||||
|
.play_sound(sound_effect_for_kind(monster.kind, &sound_effects));
|
||||||
|
let _ = entities.delete(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map.clear_tile_content_at(Point::from(*pos));
|
||||||
|
|
||||||
|
pos.x = destination.x;
|
||||||
|
pos.y = destination.y;
|
||||||
|
|
||||||
|
map.set_tile_content_at(destination, player_entity);
|
||||||
|
|
||||||
|
TimeSystem::force_tick(&mut clock);
|
||||||
|
|
||||||
|
sound_output.play_sound(sound_effects.step.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let static_sound = sound_effects.get_new_static_effect(&sound_output);
|
||||||
|
sound_output.play_sound(static_sound);
|
||||||
|
}
|
||||||
|
|
||||||
|
player.last_moved = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn whip(world: &World) {
|
||||||
|
let entities = world.entities();
|
||||||
|
|
||||||
|
let players = world.read_storage::<Player>();
|
||||||
|
let positions = world.read_storage::<Position>();
|
||||||
|
let mut wants_to_whips = world.write_storage::<WantsToWhip>();
|
||||||
|
|
||||||
|
let mut stats = world.write_resource::<Stats>();
|
||||||
|
let mut sound_output = world.write_resource::<SoundOutput>();
|
||||||
|
let sound_effects = world.fetch::<SoundEffects>();
|
||||||
|
|
||||||
|
for (entity, _player, _position) in (&entities, &players, &positions).join() {
|
||||||
|
if wants_to_whips.get(entity).is_none() && stats.whips > 0 {
|
||||||
|
let _ = wants_to_whips.insert(
|
||||||
|
entity,
|
||||||
|
WantsToWhip {
|
||||||
|
frame: 0,
|
||||||
|
last_frame: Instant::now(),
|
||||||
|
sound: Some(sound_output.play_sound(sound_effects.whipping.clone())),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
stats.whips -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
src/main.rs
38
src/main.rs
|
@ -3,13 +3,13 @@
|
||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod difficulty;
|
pub mod difficulty;
|
||||||
|
mod graphics;
|
||||||
|
pub mod input;
|
||||||
pub mod levels;
|
pub mod levels;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
mod sidebar;
|
|
||||||
mod state;
|
mod state;
|
||||||
pub mod systems;
|
pub mod systems;
|
||||||
pub mod tile_data;
|
pub mod tile_data;
|
||||||
pub mod vga_color;
|
|
||||||
|
|
||||||
use bracket_lib::prelude::*;
|
use bracket_lib::prelude::*;
|
||||||
use components::{Monster, Player, Position, Renderable, WantsToWhip};
|
use components::{Monster, Player, Position, Renderable, WantsToWhip};
|
||||||
|
@ -30,23 +30,23 @@ fn main() -> BError {
|
||||||
let sound_effects = SoundEffects::new(&sound_system);
|
let sound_effects = SoundEffects::new(&sound_system);
|
||||||
sound_system.play_sound(sound_effects.startup.clone());
|
sound_system.play_sound(sound_effects.startup.clone());
|
||||||
|
|
||||||
let mut ecs = World::new();
|
let mut world = World::new();
|
||||||
|
|
||||||
let starting_level = 0;
|
let starting_level = 0;
|
||||||
ecs.insert(sound_system);
|
world.insert(sound_system);
|
||||||
ecs.insert(LevelNumber(starting_level));
|
world.insert(LevelNumber(starting_level));
|
||||||
ecs.insert(ShowDebugInfo(false));
|
world.insert(ShowDebugInfo(false));
|
||||||
ecs.insert(StopClock(false));
|
world.insert(StopClock(false));
|
||||||
ecs.insert(Clock {
|
world.insert(Clock {
|
||||||
last_ticked: Instant::now(),
|
last_ticked: Instant::now(),
|
||||||
has_ticked: false,
|
has_ticked: false,
|
||||||
ticks: 0,
|
ticks: 0,
|
||||||
});
|
});
|
||||||
ecs.insert(sound_effects);
|
world.insert(sound_effects);
|
||||||
|
|
||||||
let selected_difficulty = difficulty::SECRET;
|
let selected_difficulty = difficulty::SECRET;
|
||||||
ecs.insert(selected_difficulty);
|
world.insert(selected_difficulty);
|
||||||
ecs.insert(Stats {
|
world.insert(Stats {
|
||||||
score: 0,
|
score: 0,
|
||||||
gems: selected_difficulty.starting_gems,
|
gems: selected_difficulty.starting_gems,
|
||||||
whips: selected_difficulty.starting_whips,
|
whips: selected_difficulty.starting_whips,
|
||||||
|
@ -55,15 +55,15 @@ fn main() -> BError {
|
||||||
keys: selected_difficulty.starting_keys,
|
keys: selected_difficulty.starting_keys,
|
||||||
});
|
});
|
||||||
|
|
||||||
ecs.register::<Position>();
|
world.register::<Position>();
|
||||||
ecs.register::<Renderable>();
|
world.register::<Renderable>();
|
||||||
ecs.register::<Monster>();
|
world.register::<Monster>();
|
||||||
ecs.register::<Player>();
|
world.register::<Player>();
|
||||||
ecs.register::<WantsToWhip>();
|
world.register::<WantsToWhip>();
|
||||||
|
|
||||||
let mut map = Map::from_level(levels::get_level(starting_level));
|
let mut map = Map::from_level(levels::get_level(starting_level));
|
||||||
map.spawn_entities(&mut ecs);
|
map.spawn_entities(&mut world);
|
||||||
ecs.insert(map);
|
world.insert(map);
|
||||||
|
|
||||||
// let descent_sounds: Vec<Sound> = (20..100)
|
// let descent_sounds: Vec<Sound> = (20..100)
|
||||||
// .rev()
|
// .rev()
|
||||||
|
@ -83,5 +83,5 @@ fn main() -> BError {
|
||||||
|
|
||||||
// let _ = gs.sound_system.play_sound(descent_effect);
|
// let _ = gs.sound_system.play_sound(descent_effect);
|
||||||
|
|
||||||
main_loop(context, State::new(ecs))
|
main_loop(context, State::new(world))
|
||||||
}
|
}
|
||||||
|
|
9
src/resources/clock.rs
Normal file
9
src/resources/clock.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
pub struct Clock {
|
||||||
|
pub last_ticked: Instant,
|
||||||
|
pub has_ticked: bool,
|
||||||
|
pub ticks: u128,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StopClock(pub bool);
|
|
@ -3,9 +3,9 @@ use std::time::Instant;
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{monster::*, Monster, Player, Position, Renderable},
|
components::{monster::*, Monster, Player, Position, Renderable},
|
||||||
constants::*,
|
constants::*,
|
||||||
|
graphics::vga_color as vga,
|
||||||
levels::Level,
|
levels::Level,
|
||||||
tile_data::{self, TileType},
|
tile_data::{self, TileType},
|
||||||
vga_color as vga,
|
|
||||||
};
|
};
|
||||||
use bracket_lib::{prelude::*, random::RandomNumberGenerator};
|
use bracket_lib::{prelude::*, random::RandomNumberGenerator};
|
||||||
use specs::{Builder, Entity, World, WorldExt};
|
use specs::{Builder, Entity, World, WorldExt};
|
||||||
|
@ -80,7 +80,7 @@ impl Map {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_entities(&mut self, ecs: &mut World) {
|
pub fn spawn_entities(&mut self, world: &mut World) {
|
||||||
for (index, tile) in self
|
for (index, tile) in self
|
||||||
.tiles
|
.tiles
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
@ -90,7 +90,7 @@ impl Map {
|
||||||
let point = Point::new(index % MAP_WIDTH, index / MAP_WIDTH);
|
let point = Point::new(index % MAP_WIDTH, index / MAP_WIDTH);
|
||||||
match tile {
|
match tile {
|
||||||
TileType::Player => {
|
TileType::Player => {
|
||||||
let player_entity = ecs
|
let player_entity = world
|
||||||
.create_entity()
|
.create_entity()
|
||||||
.with(Position {
|
.with(Position {
|
||||||
x: point.x,
|
x: point.x,
|
||||||
|
@ -105,13 +105,12 @@ impl Map {
|
||||||
last_moved: Instant::now(),
|
last_moved: Instant::now(),
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
ecs.insert(point);
|
|
||||||
ecs.insert(player_entity);
|
|
||||||
self.tile_content[index] = Some(player_entity);
|
self.tile_content[index] = Some(player_entity);
|
||||||
}
|
}
|
||||||
TileType::Slow => {
|
TileType::Slow => {
|
||||||
let mut rng = RandomNumberGenerator::new();
|
let mut rng = RandomNumberGenerator::new();
|
||||||
ecs.create_entity()
|
world
|
||||||
|
.create_entity()
|
||||||
.with(Position {
|
.with(Position {
|
||||||
x: point.x,
|
x: point.x,
|
||||||
y: point.y,
|
y: point.y,
|
||||||
|
@ -131,7 +130,8 @@ impl Map {
|
||||||
}
|
}
|
||||||
TileType::Medium => {
|
TileType::Medium => {
|
||||||
let mut rng = RandomNumberGenerator::new();
|
let mut rng = RandomNumberGenerator::new();
|
||||||
ecs.create_entity()
|
world
|
||||||
|
.create_entity()
|
||||||
.with(Position {
|
.with(Position {
|
||||||
x: point.x,
|
x: point.x,
|
||||||
y: point.y,
|
y: point.y,
|
||||||
|
@ -151,7 +151,8 @@ impl Map {
|
||||||
}
|
}
|
||||||
TileType::Fast => {
|
TileType::Fast => {
|
||||||
let mut rng = RandomNumberGenerator::new();
|
let mut rng = RandomNumberGenerator::new();
|
||||||
ecs.create_entity()
|
world
|
||||||
|
.create_entity()
|
||||||
.with(Position {
|
.with(Position {
|
||||||
x: point.x,
|
x: point.x,
|
||||||
y: point.y,
|
y: point.y,
|
||||||
|
@ -199,9 +200,9 @@ impl Map {
|
||||||
&self.tiles
|
&self.tiles
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self, ctx: &mut BTerm) {
|
pub fn draw(&self, bterm: &mut BTerm) {
|
||||||
// Border
|
// Border
|
||||||
ctx.fill_region(
|
bterm.fill_region(
|
||||||
Rect {
|
Rect {
|
||||||
x1: MAP_X as i32 - 1,
|
x1: MAP_X as i32 - 1,
|
||||||
x2: MAP_WIDTH as i32 + MAP_X as i32 + 1,
|
x2: MAP_WIDTH as i32 + MAP_X as i32 + 1,
|
||||||
|
@ -218,7 +219,7 @@ impl Map {
|
||||||
let (x, y) = (point.x as usize, point.y as usize);
|
let (x, y) = (point.x as usize, point.y as usize);
|
||||||
|
|
||||||
let data = tile_data::tile_data(*tile);
|
let data = tile_data::tile_data(*tile);
|
||||||
ctx.set(
|
bterm.set(
|
||||||
x + MAP_X,
|
x + MAP_X,
|
||||||
y + MAP_Y,
|
y + MAP_Y,
|
||||||
if *tile == TileType::Gem {
|
if *tile == TileType::Gem {
|
||||||
|
|
|
@ -1,52 +1,22 @@
|
||||||
|
pub mod clock;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod sound_effects;
|
pub mod sound_effects;
|
||||||
pub mod sound_output;
|
pub mod sound_output;
|
||||||
|
|
||||||
|
use bracket_lib::prelude::*;
|
||||||
|
pub use clock::{Clock, StopClock};
|
||||||
pub use map::Map;
|
pub use map::Map;
|
||||||
pub use sound_effects::SoundEffects;
|
pub use sound_effects::SoundEffects;
|
||||||
pub use sound_output::SoundOutput;
|
pub use sound_output::SoundOutput;
|
||||||
|
|
||||||
use crate::constants::CLOCK_PERIOD;
|
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct LevelNumber(pub u32);
|
pub struct LevelNumber(pub u32);
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ShowDebugInfo(pub bool);
|
pub struct ShowDebugInfo(pub bool);
|
||||||
|
|
||||||
pub struct Clock {
|
#[derive(Default)]
|
||||||
pub last_ticked: Instant,
|
pub struct PlayerInput(pub Option<VirtualKeyCode>);
|
||||||
pub has_ticked: bool,
|
|
||||||
pub ticks: u128,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clock {
|
|
||||||
pub fn try_tick(&mut self) {
|
|
||||||
if Instant::now() - self.last_ticked > Duration::from_secs_f32(CLOCK_PERIOD) {
|
|
||||||
self.tick();
|
|
||||||
} else {
|
|
||||||
self.has_ticked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn force_tick(&mut self) {
|
|
||||||
self.tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tick(&mut self) {
|
|
||||||
self.has_ticked = true;
|
|
||||||
self.last_ticked = Instant::now();
|
|
||||||
self.ticks += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.last_ticked = Instant::now();
|
|
||||||
self.has_ticked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct StopClock(pub bool);
|
|
||||||
|
|
||||||
pub struct Stats {
|
pub struct Stats {
|
||||||
pub score: u32,
|
pub score: u32,
|
||||||
|
|
240
src/state.rs
240
src/state.rs
|
@ -1,245 +1,23 @@
|
||||||
use std::time::{Duration, Instant};
|
use crate::graphics::draw;
|
||||||
|
use crate::input::handle;
|
||||||
use crate::components::monster::damage_for_kind;
|
|
||||||
use crate::components::monster::sound_effect_for_kind;
|
|
||||||
use crate::components::*;
|
|
||||||
use crate::resources::*;
|
|
||||||
use crate::systems::*;
|
use crate::systems::*;
|
||||||
use crate::vga_color as vga;
|
|
||||||
use crate::{constants::*, sidebar};
|
|
||||||
use bracket_lib::prelude::*;
|
use bracket_lib::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
ecs: World,
|
world: World,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameState for State {
|
impl GameState for State {
|
||||||
fn tick(&mut self, ctx: &mut BTerm) {
|
fn tick(&mut self, bterm: &mut BTerm) {
|
||||||
ctx.cls();
|
handle(&self.world, bterm);
|
||||||
|
run_systems(&mut self.world);
|
||||||
self.handle_input(ctx);
|
draw(&self.world, bterm);
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.draw_whip(ctx);
|
|
||||||
|
|
||||||
sidebar::draw(&self.ecs, ctx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn new(ecs: World) -> Self {
|
pub fn new(world: World) -> Self {
|
||||||
State { ecs }
|
State { world }
|
||||||
}
|
|
||||||
|
|
||||||
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::W => {
|
|
||||||
let player_entity = self.ecs.read_resource::<Entity>();
|
|
||||||
let mut stats = self.ecs.write_resource::<Stats>();
|
|
||||||
let positions = self.ecs.read_storage::<Position>();
|
|
||||||
let mut wants_to_whips = self.ecs.write_storage::<WantsToWhip>();
|
|
||||||
if let Some(_position) = positions.get(*player_entity) {
|
|
||||||
if wants_to_whips.get(*player_entity).is_none() && stats.whips > 0 {
|
|
||||||
let mut sound_output = self.ecs.write_resource::<SoundOutput>();
|
|
||||||
let sound_effects = self.ecs.fetch::<SoundEffects>();
|
|
||||||
let _ = wants_to_whips.insert(
|
|
||||||
*player_entity,
|
|
||||||
WantsToWhip {
|
|
||||||
frame: 0,
|
|
||||||
last_frame: Instant::now(),
|
|
||||||
sound: Some(
|
|
||||||
sound_output.play_sound(sound_effects.whipping.clone()),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
stats.whips -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VirtualKeyCode::S => {
|
|
||||||
let mut sound_system = self.ecs.write_resource::<SoundOutput>();
|
|
||||||
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 | VirtualKeyCode::Q => {
|
|
||||||
ctx.quit();
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let mut sound_system = self.ecs.write_resource::<SoundOutput>();
|
|
||||||
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 monsters = self.ecs.write_storage::<Monster>();
|
|
||||||
let mut map = self.ecs.write_resource::<Map>();
|
|
||||||
let mut stats = self.ecs.write_resource::<Stats>();
|
|
||||||
let mut sound_output = self.ecs.write_resource::<SoundOutput>();
|
|
||||||
let wants_to_whips = self.ecs.read_storage::<WantsToWhip>();
|
|
||||||
|
|
||||||
for (player_entity, player, pos) in (&entities, &mut players, &mut positions).join() {
|
|
||||||
// The player shouldn't be able to move while whipping
|
|
||||||
if let Some(_wants_to_whip) = wants_to_whips.get(player_entity) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_output.play_sound(sound_effects.blocked.clone());
|
|
||||||
} else {
|
|
||||||
if let Some(e) = map.get_tile_content_at(destination) {
|
|
||||||
if let Some(monster) = monsters.get(e) {
|
|
||||||
stats.add_score(damage_for_kind(monster.kind));
|
|
||||||
stats.take_gems(damage_for_kind(monster.kind));
|
|
||||||
sound_output.play_sound(sound_effect_for_kind(
|
|
||||||
monster.kind,
|
|
||||||
&sound_effects,
|
|
||||||
));
|
|
||||||
let _ = entities.delete(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
map.clear_tile_content_at(Point::from(*pos));
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
map.set_tile_content_at(destination, player_entity);
|
|
||||||
|
|
||||||
self.ecs.write_resource::<Clock>().force_tick();
|
|
||||||
|
|
||||||
sound_output.play_sound(sound_effects.step.clone());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let static_sound = sound_effects.get_new_static_effect(&sound_output);
|
|
||||||
sound_output.play_sound(static_sound);
|
|
||||||
}
|
|
||||||
|
|
||||||
player.last_moved = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw_whip(&self, ctx: &mut BTerm) {
|
|
||||||
let positions = self.ecs.read_storage::<Position>();
|
|
||||||
let wants_to_whips = self.ecs.read_storage::<WantsToWhip>();
|
|
||||||
let map = self.ecs.read_resource::<Map>();
|
|
||||||
let mut rng = RandomNumberGenerator::new();
|
|
||||||
for (position, wants_to_whip) in (&positions, &wants_to_whips).join() {
|
|
||||||
let color = RGB::named(vga::get_by_index(rng.range(1, 16)));
|
|
||||||
let mut rendered_frame = wants_to_whip.frame;
|
|
||||||
let frame_data = loop {
|
|
||||||
let frame_data = match rendered_frame {
|
|
||||||
0 => Some((-1, -1, '\\')),
|
|
||||||
1 => Some((-1, 0, '─')),
|
|
||||||
2 => Some((-1, 1, '/')),
|
|
||||||
3 => Some((0, 1, '│')),
|
|
||||||
4 => Some((1, 1, '\\')),
|
|
||||||
5 => Some((1, 0, '─')),
|
|
||||||
6 => Some((1, -1, '/')),
|
|
||||||
7 => Some((0, -1, '│')),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(data) = frame_data {
|
|
||||||
let dest = Point {
|
|
||||||
x: position.x + data.0,
|
|
||||||
y: position.y + data.1,
|
|
||||||
};
|
|
||||||
if map.in_bounds(dest) {
|
|
||||||
break frame_data;
|
|
||||||
}
|
|
||||||
rendered_frame += 1;
|
|
||||||
if rendered_frame > 7 {
|
|
||||||
break None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if let Some(data) = frame_data {
|
|
||||||
ctx.set(
|
|
||||||
(position.x + MAP_X as i32) + data.0,
|
|
||||||
(position.y + MAP_Y as i32) + data.1,
|
|
||||||
color,
|
|
||||||
RGB::named(vga::BLACK),
|
|
||||||
to_cp437(data.2),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_systems(&mut self) {
|
|
||||||
let mut whip_system = WhipSystem {};
|
|
||||||
whip_system.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut monster_ai_system = MonsterAiSystem {};
|
|
||||||
monster_ai_system.run_now(&self.ecs);
|
|
||||||
|
|
||||||
self.ecs.maintain();
|
|
||||||
|
|
||||||
let mut clock = self.ecs.write_resource::<Clock>();
|
|
||||||
if !self.ecs.read_resource::<StopClock>().0 {
|
|
||||||
clock.try_tick();
|
|
||||||
} else {
|
|
||||||
clock.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,21 @@
|
||||||
pub mod monster_ai_system;
|
pub mod monster_ai_system;
|
||||||
|
pub mod time_system;
|
||||||
pub mod whip_system;
|
pub mod whip_system;
|
||||||
|
|
||||||
pub use monster_ai_system::MonsterAiSystem;
|
pub use monster_ai_system::MonsterAiSystem;
|
||||||
|
use specs::prelude::*;
|
||||||
|
pub use time_system::TimeSystem;
|
||||||
pub use whip_system::WhipSystem;
|
pub use whip_system::WhipSystem;
|
||||||
|
|
||||||
|
pub fn run_systems(world: &mut World) {
|
||||||
|
let mut whip_system = WhipSystem {};
|
||||||
|
whip_system.run_now(world);
|
||||||
|
|
||||||
|
let mut monster_ai_system = MonsterAiSystem {};
|
||||||
|
monster_ai_system.run_now(world);
|
||||||
|
|
||||||
|
let mut time_system = TimeSystem {};
|
||||||
|
time_system.run_now(world);
|
||||||
|
|
||||||
|
world.maintain();
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ impl<'a> System<'a> for MonsterAiSystem {
|
||||||
type SystemData = (
|
type SystemData = (
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
ReadExpect<'a, Clock>,
|
ReadExpect<'a, Clock>,
|
||||||
ReadExpect<'a, Point>,
|
|
||||||
WriteExpect<'a, Map>,
|
WriteExpect<'a, Map>,
|
||||||
WriteExpect<'a, Stats>,
|
WriteExpect<'a, Stats>,
|
||||||
ReadExpect<'a, SoundEffects>,
|
ReadExpect<'a, SoundEffects>,
|
||||||
|
@ -32,7 +31,6 @@ impl<'a> System<'a> for MonsterAiSystem {
|
||||||
(
|
(
|
||||||
entities,
|
entities,
|
||||||
clock,
|
clock,
|
||||||
player_pos,
|
|
||||||
mut map,
|
mut map,
|
||||||
mut stats,
|
mut stats,
|
||||||
sound_effects,
|
sound_effects,
|
||||||
|
@ -43,6 +41,12 @@ impl<'a> System<'a> for MonsterAiSystem {
|
||||||
players,
|
players,
|
||||||
): Self::SystemData,
|
): 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)
|
let mut data = (&entities, &mut monsters, &mut positions, &mut renderables)
|
||||||
.join()
|
.join()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
@ -83,8 +87,10 @@ impl<'a> System<'a> for MonsterAiSystem {
|
||||||
// TODO: Sound
|
// TODO: Sound
|
||||||
map.clear_tile_content_at(Point::from(**position));
|
map.clear_tile_content_at(Point::from(**position));
|
||||||
stats.take_gems(damage_for_kind(monster.kind));
|
stats.take_gems(damage_for_kind(monster.kind));
|
||||||
sound_output
|
sound_output.play_sound(sound_effect_for_kind(
|
||||||
.play_sound(sound_effect_for_kind(monster.kind, &sound_effects));
|
monster.kind,
|
||||||
|
&sound_effects,
|
||||||
|
));
|
||||||
let _ = entities.delete(*entity);
|
let _ = entities.delete(*entity);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -110,4 +116,5 @@ impl<'a> System<'a> for MonsterAiSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
45
src/systems/time_system.rs
Normal file
45
src/systems/time_system.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use crate::constants::CLOCK_PERIOD;
|
||||||
|
use specs::prelude::*;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use crate::resources::{Clock, StopClock};
|
||||||
|
|
||||||
|
pub struct TimeSystem {}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
impl<'a> System<'a> for TimeSystem {
|
||||||
|
type SystemData = (WriteExpect<'a, Clock>, ReadExpect<'a, StopClock>);
|
||||||
|
|
||||||
|
fn run(&mut self, (mut clock, stop_clock): Self::SystemData) {
|
||||||
|
if !stop_clock.0 {
|
||||||
|
Self::try_tick(&mut clock);
|
||||||
|
} else {
|
||||||
|
Self::reset(&mut clock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimeSystem {
|
||||||
|
pub fn try_tick(clock: &mut Clock) {
|
||||||
|
if Instant::now() - clock.last_ticked > Duration::from_secs_f32(CLOCK_PERIOD) {
|
||||||
|
Self::tick(clock);
|
||||||
|
} else {
|
||||||
|
clock.has_ticked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn force_tick(clock: &mut Clock) {
|
||||||
|
Self::tick(clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick(clock: &mut Clock) {
|
||||||
|
clock.has_ticked = true;
|
||||||
|
clock.last_ticked = Instant::now();
|
||||||
|
clock.ticks += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(clock: &mut Clock) {
|
||||||
|
clock.last_ticked = Instant::now();
|
||||||
|
clock.has_ticked = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use bracket_lib::prelude::*;
|
use bracket_lib::prelude::*;
|
||||||
|
|
||||||
use crate::vga_color as vga;
|
use crate::graphics::vga_color as vga;
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
pub struct TileData {
|
pub struct TileData {
|
||||||
|
|
Loading…
Add table
Reference in a new issue