diff --git a/src/levels.rs b/src/levels.rs new file mode 100644 index 0000000..a0039b6 --- /dev/null +++ b/src/levels.rs @@ -0,0 +1,56 @@ +use std::collections::HashMap; + +use crate::{constants::*, tile_data::TileType}; + +#[allow(clippy::large_enum_variant)] +pub enum Level { + Normal([&'static str; MAP_HEIGHT]), + Randomized(HashMap), + End, +} + +pub fn get_level(index: u32) -> Level { + match index { + 0 => Level::Randomized(HashMap::from([ + (TileType::Slow, 15), + (TileType::Whip, 1), + (TileType::Stairs, 3), + (TileType::Gem, 8), + ])), + 1 => Level::Normal([ + "LXXX2 2 2 2 2 2 2 2 2 2 2 2 2 +", + "+XXX 2 2 2 2 2 2 2 2 XXX ", + " XXX2 2 2 2 2 2 2 2 2 2 2 XTX ", + "+XXX 2 2 2 2 2 2 2 XXX ", + " XXX 2 2 2 2 2 2 2 2 2 2 ", + "+XXX 2 ", + " XXX 2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2 2 ", + "+XXX2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2 ", + " XXX 2 XXX2 W 2XXX 2 ", + "+XXX 2 XXX 2 FFFFF 2 XXX 2 2 ", + " XXX2 2 XXX F111F XXX ", + "+XXX2 XXX+ 3 3 W F1P1F W 3 3 +XXX 2 ", + "XXXX 2 XXX F111F XXX 2 2", + "WXXX 2 XXX 2 FFFFF 2 XXX 2 ", + "WXXX2 XXX2 W 2XXX 2 ", + "WXXX 2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2 ", + "WXXX 2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2 ", + "WXXX2 2 ", + "WXXX 2 2 2 2 2 2 2 2 2 2 2 ", + "XXXX 2 2 2 2 2 2 2 2 2 2 2 XXX ", + "XXXX2 2 2 2 2 2 2 2 2 2 2 2 XTX ", + "XXXX 2 2 2 2 2 2 2 2 2 2 2 2 XXX ", + "CXXX 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +", + ]), + 2 => Level::Randomized(HashMap::from([ + (TileType::Slow, 60), + (TileType::Block, 25), + (TileType::Whip, 5), + (TileType::Stairs, 2), + (TileType::Gem, 10), + (TileType::Teleport, 3), + ])), + 40 => Level::End, + _ => Level::Randomized(HashMap::new()), + } +} diff --git a/src/main.rs b/src/main.rs index 136d7d9..af74b14 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ pub mod components; pub mod constants; +pub mod levels; pub mod resources; mod sidebar; mod state; @@ -10,23 +11,17 @@ pub mod tile_data; pub mod vga_color; use bracket_lib::prelude::*; -use components::{ - monster::{color_for_kind, glyphs_for_kind, ticks_for_kind, MonsterKind}, - Monster, Player, Position, Renderable, -}; +use components::{Monster, Player, Position, Renderable}; use resources::{Clock, LevelNumber, Map, ShowDebugInfo, SoundEffects, SoundOutput, Stats}; use specs::prelude::*; use state::State; use std::time::Instant; -use tile_data::TileType; - -use vga_color as vga; fn main() -> BError { - let context = BTermBuilder::simple(80, 25)? + let context = BTermBuilder::vga(80, 25) + // .with_tile_dimensions(8, 16) .with_fps_cap(60.0) .with_title("Kroz") - .with_tile_dimensions(8, 16) .build()?; let mut ss = SoundOutput::new(); @@ -57,69 +52,10 @@ fn main() -> BError { ecs.register::(); ecs.register::(); - let map = Map::new(); - let mut rng = RandomNumberGenerator::new(); - for (i, tile) in &mut map.get_tiles().iter().enumerate() { - if rng.roll_dice(1, 16) < 2 && *tile == TileType::Floor { - let position = map.index_to_point2d(i); - let kind = match rng.range(0, 3) { - 0 => MonsterKind::Slow, - 1 => MonsterKind::Medium, - 2 => MonsterKind::Fast, - _ => MonsterKind::Slow, - }; - ecs.create_entity() - .with(Position { - x: position.x, - y: position.y, - }) - .with(Renderable { - glyph: *rng.random_slice_entry(&glyphs_for_kind(kind)).unwrap(), - fg: color_for_kind(kind), - bg: RGB::named(vga::BLACK), - }) - .with(Monster { - kind, - ticks_until_move: ticks_for_kind(kind), - }) - .build(); - } - } - - let player_start_pos = Point { x: 40, y: 22 }; - - ecs.create_entity() - .with(Position { - x: player_start_pos.x, - y: player_start_pos.y, - }) - .with(Renderable { - glyph: to_cp437('☻'), - fg: RGB::named(vga::YELLOW_BRIGHT), - bg: RGB::named(vga::BLACK), - }) - .with(Player { - last_moved: Instant::now(), - }) - .build(); - + let map = Map::from_level(levels::get_level(0)); + map.spawn_entities(&mut ecs); ecs.insert(map); - ecs.insert(Point::new(player_start_pos.x, player_start_pos.y)); - - // for i in 0..10 { - // gs.ecs - // .create_entity() - // .with(Position { x: i * 7, y: 20 }) - // .with(Renderable { - // glyph: to_cp437('Ä'), - // fg: RGB::named(vga::RED_BRIGHT), - // bg: RGB::named(vga::BLACK), - // }) - // .with(LeftMover {}) - // .build(); - // } - // let descent_sounds: Vec = (20..100) // .rev() // .flat_map(|x| { diff --git a/src/resources/map.rs b/src/resources/map.rs index 3e72d57..e196fe7 100644 --- a/src/resources/map.rs +++ b/src/resources/map.rs @@ -1,10 +1,14 @@ +use std::time::Instant; + use crate::{ - constants::{MAP_HEIGHT, MAP_SIZE, MAP_WIDTH, MAP_X, MAP_Y}, + components::{monster::*, Monster, Player, Position, Renderable}, + constants::*, + levels::Level, tile_data::{self, TileType}, vga_color as vga, }; use bracket_lib::{prelude::*, random::RandomNumberGenerator}; -use specs::Entity; +use specs::{Builder, Entity, World, WorldExt}; pub struct Map { tiles: Vec, @@ -29,23 +33,137 @@ impl Default for Map { impl Map { pub fn new() -> Self { - let mut tiles = vec![TileType::Floor; MAP_SIZE]; let mut rng = RandomNumberGenerator::new(); - for tile in &mut tiles { - if rng.roll_dice(1, 16) < 2 { - *tile = TileType::Wall; - } else if rng.roll_dice(1, 16) < 2 { - *tile = TileType::Block; - } - } Self { - tiles, + tiles: vec![TileType::Floor; MAP_SIZE], tile_content: vec![None; MAP_SIZE], border_fg: RGB::named(vga::get_by_index(rng.range(8, 15))), border_bg: RGB::named(vga::get_by_index(rng.range(1, 7) as usize)), } } + pub fn from_level(level: Level) -> Self { + match level { + Level::Normal(_data) => todo!(), + Level::Randomized(data) => { + let mut rng = RandomNumberGenerator::new(); + let mut map = Self::new(); + for (tile, count) in data { + for _ in 0..count { + loop { + let point = Point { + x: rng.range(0, MAP_WIDTH as i32), + y: rng.range(0, MAP_HEIGHT as i32), + }; + if map.get_tile_at(point) == TileType::Floor { + map.set_tile_at(point, tile); + break; + } + } + } + } + loop { + let point = Point { + x: rng.range(0, MAP_WIDTH as i32), + y: rng.range(0, MAP_HEIGHT as i32), + }; + if map.get_tile_at(point) == TileType::Floor { + map.set_tile_at(point, TileType::Player); + break; + } + } + map + } + Level::End => todo!(), + } + } + + pub fn spawn_entities(&self, ecs: &mut World) { + for (index, tile) in self.tiles.iter().enumerate() { + let point = self.index_to_point2d(index); + match tile { + TileType::Player => { + ecs.create_entity() + .with(Position { + x: point.x, + y: point.y, + }) + .with(Renderable { + glyph: to_cp437('☻'), + fg: RGB::named(vga::YELLOW_BRIGHT), + bg: RGB::named(vga::BLACK), + }) + .with(Player { + last_moved: Instant::now(), + }) + .build(); + ecs.insert(point); + } + TileType::Slow => { + let mut rng = RandomNumberGenerator::new(); + ecs.create_entity() + .with(Position { + x: point.x, + y: point.y, + }) + .with(Renderable { + glyph: *rng + .random_slice_entry(&glyphs_for_kind(MonsterKind::Slow)) + .unwrap(), + fg: color_for_kind(MonsterKind::Slow), + bg: RGB::named(vga::BLACK), + }) + .with(Monster { + kind: MonsterKind::Slow, + ticks_until_move: ticks_for_kind(MonsterKind::Slow), + }) + .build(); + } + TileType::Medium => { + let mut rng = RandomNumberGenerator::new(); + ecs.create_entity() + .with(Position { + x: point.x, + y: point.y, + }) + .with(Renderable { + glyph: *rng + .random_slice_entry(&glyphs_for_kind(MonsterKind::Medium)) + .unwrap(), + fg: color_for_kind(MonsterKind::Medium), + bg: RGB::named(vga::BLACK), + }) + .with(Monster { + kind: MonsterKind::Medium, + ticks_until_move: ticks_for_kind(MonsterKind::Medium), + }) + .build(); + } + TileType::Fast => { + let mut rng = RandomNumberGenerator::new(); + ecs.create_entity() + .with(Position { + x: point.x, + y: point.y, + }) + .with(Renderable { + glyph: *rng + .random_slice_entry(&glyphs_for_kind(MonsterKind::Fast)) + .unwrap(), + fg: color_for_kind(MonsterKind::Fast), + bg: RGB::named(vga::BLACK), + }) + .with(Monster { + kind: MonsterKind::Fast, + ticks_until_move: ticks_for_kind(MonsterKind::Fast), + }) + .build(); + } + _ => {} + } + } + } + pub fn clear_all_tile_content(&mut self) { self.tile_content.iter_mut().for_each(|tile| { *tile = None; diff --git a/src/tile_data.rs b/src/tile_data.rs index 2c40e3d..296780a 100644 --- a/src/tile_data.rs +++ b/src/tile_data.rs @@ -11,9 +11,12 @@ pub struct TileData { pub blink: bool, } -#[derive(PartialEq, Copy, Clone)] +#[derive(Eq, PartialEq, Copy, Clone, Hash)] pub enum TileType { Floor, // 0 + Slow, // 1 + Medium, // 2 + Fast, // 3 Block, // 4 Whip, // 5 Stairs, // 6 @@ -72,6 +75,27 @@ pub fn tile_data(tile: TileType) -> TileData { color_bg: vga::BLACK, blink: false, }, + TileType::Slow => TileData { + glyph: 0, + serialized_char: '1', + color_fg: vga::BLACK, + color_bg: vga::BLACK, + blink: false, + }, + TileType::Medium => TileData { + glyph: 0, + serialized_char: '2', + color_fg: vga::BLACK, + color_bg: vga::BLACK, + blink: false, + }, + TileType::Fast => TileData { + glyph: 0, + serialized_char: '3', + color_fg: vga::BLACK, + color_bg: vga::BLACK, + blink: false, + }, TileType::Block => TileData { glyph: to_cp437('▓'), serialized_char: 'X',