Implement randomized levels
This commit is contained in:
parent
29a1a2bc7f
commit
62905dc330
4 changed files with 216 additions and 82 deletions
56
src/levels.rs
Normal file
56
src/levels.rs
Normal 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()),
|
||||
}
|
||||
}
|
76
src/main.rs
76
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::<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| {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Add table
Reference in a new issue