Create a rough town map generator, starting section 5.4
This commit is contained in:
parent
5d7f9e509f
commit
2dc420bef9
@ -1,5 +1,5 @@
|
||||
use rltk::{Point, Rltk, RGB};
|
||||
use specs::prelude::*;
|
||||
use ::rltk::{Point, Rltk, RGB};
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use crate::{Hidden, Map, Position, Renderable, TileType};
|
||||
|
||||
@ -127,25 +127,22 @@ pub fn render_debug_map(map: &Map, ctx: &mut Rltk) {
|
||||
}
|
||||
|
||||
fn get_tile_glyph(idx: usize, map: &Map) -> (rltk::FontCharType, RGB, RGB) {
|
||||
let glyph;
|
||||
let mut fg;
|
||||
let mut bg = RGB::from_f32(0., 0., 0.);
|
||||
|
||||
match map.tiles[idx] {
|
||||
TileType::Floor => {
|
||||
glyph = rltk::to_cp437('.');
|
||||
fg = RGB::from_f32(0., 0.5, 0.5);
|
||||
}
|
||||
let (glyph, mut fg) = match map.tiles[idx] {
|
||||
TileType::Floor => (rltk::to_cp437('.'), RGB::from_f32(0., 0.5, 0.5)),
|
||||
TileType::WoodFloor => (rltk::to_cp437('.'), RGB::named(rltk::CHOCOLATE)),
|
||||
TileType::Wall => {
|
||||
let x = idx as i32 % map.width;
|
||||
let y = idx as i32 / map.width;
|
||||
glyph = wall_glyph(&*map, x, y);
|
||||
fg = RGB::from_f32(0., 1.0, 0.);
|
||||
}
|
||||
TileType::DownStairs => {
|
||||
glyph = rltk::to_cp437('>');
|
||||
fg = RGB::from_f32(0., 1.0, 1.0);
|
||||
(wall_glyph(&*map, x, y), RGB::from_f32(0., 1.0, 0.))
|
||||
}
|
||||
TileType::DownStairs => (rltk::to_cp437('>'), RGB::from_f32(0., 1.0, 1.0)),
|
||||
TileType::Bridge => (rltk::to_cp437('.'), RGB::named(rltk::CHOCOLATE)),
|
||||
TileType::Road => (rltk::to_cp437('~'), RGB::named(rltk::GRAY)),
|
||||
TileType::Grass => (rltk::to_cp437('"'), RGB::named(rltk::GREEN)),
|
||||
TileType::ShallowWater => (rltk::to_cp437('≈'), RGB::named(rltk::CYAN)),
|
||||
TileType::DeepWater => (rltk::to_cp437('≈'), RGB::named(rltk::NAVY_BLUE)),
|
||||
};
|
||||
|
||||
if map.bloodstains.contains(&idx) {
|
||||
|
@ -24,6 +24,9 @@ mod visibility_system;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
use ::rltk::{GameState, Point, RandomNumberGenerator, Rltk};
|
||||
use ::specs::prelude::*;
|
||||
use ::specs::saveload::{SimpleMarker, SimpleMarkerAllocator};
|
||||
use components::*;
|
||||
use damage_system::DamageSystem;
|
||||
pub use game_log::GameLog;
|
||||
@ -34,9 +37,6 @@ use melee_combat_system::MeleeCombatSystem;
|
||||
use monster_ai_system::MonsterAI;
|
||||
use player::*;
|
||||
pub use rect::Rect;
|
||||
use rltk::{GameState, Point, RandomNumberGenerator, Rltk};
|
||||
use specs::prelude::*;
|
||||
use specs::saveload::{SimpleMarker, SimpleMarkerAllocator};
|
||||
use visibility_system::VisibilitySystem;
|
||||
|
||||
/// Cut down on the amount of syntax to register components
|
||||
@ -450,7 +450,7 @@ impl State {
|
||||
self.mapgen_history.clear();
|
||||
|
||||
let mut rng = self.ecs.write_resource::<RandomNumberGenerator>();
|
||||
let mut builder = map_builders::random_builder(new_depth, &mut rng, 80, 50);
|
||||
let mut builder = map_builders::level_builder(new_depth, &mut rng, 80, 50);
|
||||
builder.build_map(&mut rng);
|
||||
|
||||
std::mem::drop(rng);
|
||||
|
41
src/map.rs
41
src/map.rs
@ -1,15 +1,13 @@
|
||||
mod tiletype;
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use rltk::{Algorithm2D, BaseMap, Point, SmallVec};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::prelude::*;
|
||||
use ::rltk::{Algorithm2D, BaseMap, Point, SmallVec};
|
||||
use ::serde::{Deserialize, Serialize};
|
||||
use ::specs::prelude::*;
|
||||
pub use tiletype::{tile_opaque, tile_walkable, TileType};
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum TileType {
|
||||
Wall,
|
||||
Floor,
|
||||
DownStairs,
|
||||
}
|
||||
use crate::map::tiletype::tile_cost;
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Clone)]
|
||||
pub struct Map {
|
||||
@ -45,7 +43,7 @@ impl Map {
|
||||
|
||||
pub fn populate_blocked(&mut self) {
|
||||
for (i, tile) in self.tiles.iter_mut().enumerate() {
|
||||
self.blocked[i] = *tile == TileType::Wall;
|
||||
self.blocked[i] = !tile_walkable(*tile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,7 +74,11 @@ impl Map {
|
||||
|
||||
impl BaseMap for Map {
|
||||
fn is_opaque(&self, idx: usize) -> bool {
|
||||
self.tiles[idx] == TileType::Wall || self.view_blocked.contains(&idx)
|
||||
if idx > 0 && idx < self.tiles.len() {
|
||||
tile_opaque(self.tiles[idx]) || self.view_blocked.contains(&idx)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn get_available_exits(&self, idx: usize) -> SmallVec<[(usize, f32); 10]> {
|
||||
@ -84,33 +86,34 @@ impl BaseMap for Map {
|
||||
let x = idx as i32 % self.width;
|
||||
let y = idx as i32 / self.width;
|
||||
let w = self.width as usize;
|
||||
let tt = self.tiles[idx];
|
||||
|
||||
// Cardinal directions
|
||||
if self.is_exit_valid(x - 1, y) {
|
||||
exits.push((idx - 1, 1.0))
|
||||
exits.push((idx - 1, tile_cost(tt)))
|
||||
};
|
||||
if self.is_exit_valid(x + 1, y) {
|
||||
exits.push((idx + 1, 1.0))
|
||||
exits.push((idx + 1, tile_cost(tt)))
|
||||
};
|
||||
if self.is_exit_valid(x, y - 1) {
|
||||
exits.push((idx - w, 1.0))
|
||||
exits.push((idx - w, tile_cost(tt)))
|
||||
};
|
||||
if self.is_exit_valid(x, y + 1) {
|
||||
exits.push((idx + w, 1.0))
|
||||
exits.push((idx + w, tile_cost(tt)))
|
||||
};
|
||||
|
||||
// Diagonals
|
||||
if self.is_exit_valid(x - 1, y - 1) {
|
||||
exits.push(((idx - w) - 1, 1.45));
|
||||
exits.push(((idx - w) - 1, tile_cost(tt) * 1.45));
|
||||
}
|
||||
if self.is_exit_valid(x + 1, y - 1) {
|
||||
exits.push(((idx - w) + 1, 1.45));
|
||||
exits.push(((idx - w) + 1, tile_cost(tt) * 1.45));
|
||||
}
|
||||
if self.is_exit_valid(x - 1, y + 1) {
|
||||
exits.push(((idx + w) - 1, 1.45));
|
||||
exits.push(((idx + w) - 1, tile_cost(tt) * 1.45));
|
||||
}
|
||||
if self.is_exit_valid(x + 1, y + 1) {
|
||||
exits.push(((idx + w) + 1, 1.45));
|
||||
exits.push(((idx + w) + 1, tile_cost(tt) * 1.45));
|
||||
}
|
||||
|
||||
exits
|
||||
|
40
src/map/tiletype.rs
Normal file
40
src/map/tiletype.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum TileType {
|
||||
Wall,
|
||||
Floor,
|
||||
DownStairs,
|
||||
Road,
|
||||
Grass,
|
||||
ShallowWater,
|
||||
DeepWater,
|
||||
WoodFloor,
|
||||
Bridge,
|
||||
}
|
||||
|
||||
pub fn tile_walkable(tt: TileType) -> bool {
|
||||
matches!(
|
||||
tt,
|
||||
TileType::Floor
|
||||
| TileType::DownStairs
|
||||
| TileType::Road
|
||||
| TileType::Grass
|
||||
| TileType::ShallowWater
|
||||
| TileType::WoodFloor
|
||||
| TileType::Bridge
|
||||
)
|
||||
}
|
||||
|
||||
pub fn tile_opaque(tt: TileType) -> bool {
|
||||
matches!(tt, TileType::Wall)
|
||||
}
|
||||
|
||||
pub fn tile_cost(tt: TileType) -> f32 {
|
||||
match tt {
|
||||
TileType::Road => 0.8,
|
||||
TileType::Grass => 1.1,
|
||||
TileType::ShallowWater => 1.2,
|
||||
_ => 1.0,
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ mod rooms_corridors_dogleg;
|
||||
mod rooms_corridors_lines;
|
||||
mod rooms_corridors_nearest;
|
||||
mod simple_map;
|
||||
mod town;
|
||||
mod voronoi;
|
||||
mod voronoi_spawning;
|
||||
mod waveform_collapse;
|
||||
@ -53,6 +54,7 @@ use rooms_corridors_lines::StraightLineCorridors;
|
||||
use rooms_corridors_nearest::NearestCorridors;
|
||||
use simple_map::SimpleMapBuilder;
|
||||
use specs::prelude::*;
|
||||
use town::town_builder;
|
||||
use voronoi::VoronoiCellBuilder;
|
||||
use voronoi_spawning::VoronoiSpawning;
|
||||
use waveform_collapse::WaveformCollapseBuilder;
|
||||
@ -175,7 +177,7 @@ pub trait MetaMapBuilder {
|
||||
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap);
|
||||
}
|
||||
|
||||
fn random_start_position(rng: &mut rltk::RandomNumberGenerator) -> (XStart, YStart) {
|
||||
pub fn random_start_position(rng: &mut rltk::RandomNumberGenerator) -> (XStart, YStart) {
|
||||
let x = match rng.roll_dice(1, 3) {
|
||||
1 => XStart::Left,
|
||||
2 => XStart::Center,
|
||||
@ -330,3 +332,16 @@ pub fn random_builder(
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
pub fn level_builder(
|
||||
new_depth: i32,
|
||||
rng: &mut RandomNumberGenerator,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> BuilderChain {
|
||||
rltk::console::log(format!("Depth: {}", new_depth));
|
||||
match new_depth {
|
||||
1 => town_builder(new_depth, rng, width, height),
|
||||
_ => random_builder(new_depth, rng, width, height),
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rltk::RandomNumberGenerator;
|
||||
|
||||
use crate::map_builders::{BuilderMap, MetaMapBuilder};
|
||||
use crate::{Position, TileType};
|
||||
use crate::{map, Position};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum XStart {
|
||||
@ -49,7 +49,7 @@ impl AreaStartingPosition {
|
||||
|
||||
let mut available_floors: Vec<(usize, f32)> = Vec::new();
|
||||
for (idx, tiletype) in build_data.map.tiles.iter().enumerate() {
|
||||
if *tiletype == TileType::Floor {
|
||||
if map::tile_walkable(*tiletype) {
|
||||
available_floors.push((
|
||||
idx,
|
||||
rltk::DistanceAlg::PythagorasSquared.distance2d(
|
||||
|
89
src/map_builders/town.rs
Normal file
89
src/map_builders/town.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use rltk::RandomNumberGenerator;
|
||||
|
||||
use super::{BuilderChain, BuilderMap, InitialMapBuilder};
|
||||
use crate::map_builders::area_starting_points::AreaStartingPosition;
|
||||
use crate::map_builders::distant_exit::DistantExit;
|
||||
use crate::TileType;
|
||||
|
||||
pub fn town_builder(
|
||||
new_depth: i32,
|
||||
rng: &mut RandomNumberGenerator,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> BuilderChain {
|
||||
let (start_x, start_y) = super::random_start_position(rng);
|
||||
let mut chain = BuilderChain::new(new_depth, width, height);
|
||||
|
||||
chain
|
||||
.start_with(TownBuilder::new())
|
||||
.with(AreaStartingPosition::new(start_x, start_y))
|
||||
.with(DistantExit::new());
|
||||
|
||||
chain
|
||||
}
|
||||
|
||||
pub struct TownBuilder {}
|
||||
|
||||
impl InitialMapBuilder for TownBuilder {
|
||||
#[allow(dead_code)]
|
||||
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
self.build_rooms(rng, build_data);
|
||||
}
|
||||
}
|
||||
|
||||
impl TownBuilder {
|
||||
pub fn new() -> Box<TownBuilder> {
|
||||
Box::new(TownBuilder {})
|
||||
}
|
||||
|
||||
pub fn build_rooms(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
self.grass_layer(build_data);
|
||||
self.water_and_piers(rng, build_data);
|
||||
|
||||
// Make visible for screenshot
|
||||
for t in build_data.map.visible_tiles.iter_mut() {
|
||||
*t = true;
|
||||
}
|
||||
build_data.take_snapshot();
|
||||
}
|
||||
|
||||
fn grass_layer(&mut self, build_data: &mut BuilderMap) {
|
||||
// We'll start with a nice layer of grass
|
||||
for t in build_data.map.tiles.iter_mut() {
|
||||
*t = TileType::Grass
|
||||
}
|
||||
build_data.take_snapshot();
|
||||
}
|
||||
|
||||
fn water_and_piers(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
let mut n = (rng.roll_dice(1, 65535) as f32) / 65535_f32;
|
||||
let mut water_width: Vec<i32> = Vec::new();
|
||||
|
||||
for y in 0..build_data.height {
|
||||
let n_water = (f32::sin(n) * 10.0) as i32 + 14 + rng.roll_dice(1, 6);
|
||||
water_width.push(n_water);
|
||||
n += 0.1;
|
||||
|
||||
for x in 0..n_water {
|
||||
let idx = build_data.map.xy_idx(x, y);
|
||||
build_data.map.tiles[idx] = TileType::DeepWater;
|
||||
}
|
||||
|
||||
for x in n_water..n_water + 3 {
|
||||
let idx = build_data.map.xy_idx(x, y);
|
||||
build_data.map.tiles[idx] = TileType::ShallowWater;
|
||||
}
|
||||
}
|
||||
build_data.take_snapshot();
|
||||
|
||||
// Add piers
|
||||
for _i in 0..rng.roll_dice(1, 4) + 6 {
|
||||
let y = rng.roll_dice(1, build_data.height) - 1;
|
||||
for x in 2 + rng.roll_dice(1, 6)..water_width[y as usize] + 4 {
|
||||
let idx = build_data.map.xy_idx(x, y);
|
||||
build_data.map.tiles[idx] = TileType::WoodFloor;
|
||||
}
|
||||
}
|
||||
build_data.take_snapshot();
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::Renderable;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct SpawnTableEntry {
|
||||
pub name: String,
|
||||
|
Loading…
Reference in New Issue
Block a user