Implement randomized levels

This commit is contained in:
Alex Page 2022-01-29 21:53:01 -05:00
parent 29a1a2bc7f
commit 62905dc330
4 changed files with 216 additions and 82 deletions

56
src/levels.rs Normal file
View file

@ -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<TileType, u32>),
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()),
}
}

View file

@ -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::<Monster>();
ecs.register::<Player>();
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<Sound> = (20..100)
// .rev()
// .flat_map(|x| {

View file

@ -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<TileType>,
@ -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;

View file

@ -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',