Refactor voronoi map builder to use Rust builder pattern
This commit is contained in:
parent
3f692846f8
commit
a6d37bf0dc
@ -1,7 +1,10 @@
|
|||||||
|
mod area_starting_points;
|
||||||
mod bsp_dungeon;
|
mod bsp_dungeon;
|
||||||
mod bsp_interior;
|
mod bsp_interior;
|
||||||
mod cellular_automata;
|
mod cellular_automata;
|
||||||
mod common;
|
mod common;
|
||||||
|
mod cull_unreachable;
|
||||||
|
mod distant_exit;
|
||||||
mod dla;
|
mod dla;
|
||||||
mod drunkard;
|
mod drunkard;
|
||||||
mod maze;
|
mod maze;
|
||||||
@ -11,14 +14,17 @@ mod room_based_stairs;
|
|||||||
mod room_based_starting_position;
|
mod room_based_starting_position;
|
||||||
mod simple_map;
|
mod simple_map;
|
||||||
mod voronoi;
|
mod voronoi;
|
||||||
|
mod voronoi_spawning;
|
||||||
mod waveform_collapse;
|
mod waveform_collapse;
|
||||||
|
|
||||||
use crate::{spawner, Map, Position, Rect, SHOW_MAPGEN_VISUALIZER};
|
|
||||||
use ::rltk::RandomNumberGenerator;
|
use ::rltk::RandomNumberGenerator;
|
||||||
|
use area_starting_points::{AreaStartingPosition, XStart, YStart};
|
||||||
use bsp_dungeon::BspDungeonBuilder;
|
use bsp_dungeon::BspDungeonBuilder;
|
||||||
use bsp_interior::BspInteriorBuilder;
|
use bsp_interior::BspInteriorBuilder;
|
||||||
use cellular_automata::CellularAutomataBuilder;
|
use cellular_automata::CellularAutomataBuilder;
|
||||||
use common::*;
|
use common::*;
|
||||||
|
use cull_unreachable::CullUnreachable;
|
||||||
|
use distant_exit::DistantExit;
|
||||||
use dla::DLABuilder;
|
use dla::DLABuilder;
|
||||||
use drunkard::DrunkardsWalkBuilder;
|
use drunkard::DrunkardsWalkBuilder;
|
||||||
use maze::MazeBuilder;
|
use maze::MazeBuilder;
|
||||||
@ -29,8 +35,11 @@ use room_based_starting_position::RoomBasedStartingPosition;
|
|||||||
use simple_map::SimpleMapBuilder;
|
use simple_map::SimpleMapBuilder;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use voronoi::VoronoiCellBuilder;
|
use voronoi::VoronoiCellBuilder;
|
||||||
|
use voronoi_spawning::VoronoiSpawning;
|
||||||
use waveform_collapse::WaveformCollapseBuilder;
|
use waveform_collapse::WaveformCollapseBuilder;
|
||||||
|
|
||||||
|
use crate::{spawner, Map, Position, Rect, SHOW_MAPGEN_VISUALIZER};
|
||||||
|
|
||||||
pub struct BuilderMap {
|
pub struct BuilderMap {
|
||||||
pub spawn_list: Vec<(usize, String)>,
|
pub spawn_list: Vec<(usize, String)>,
|
||||||
pub map: Map,
|
pub map: Map,
|
||||||
@ -40,6 +49,16 @@ pub struct BuilderMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BuilderMap {
|
impl BuilderMap {
|
||||||
|
fn new(new_depth: i32) -> BuilderMap {
|
||||||
|
BuilderMap {
|
||||||
|
spawn_list: Vec::new(),
|
||||||
|
map: Map::new(new_depth),
|
||||||
|
starting_position: None,
|
||||||
|
rooms: None,
|
||||||
|
history: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn take_snapshot(&mut self) {
|
fn take_snapshot(&mut self) {
|
||||||
if SHOW_MAPGEN_VISUALIZER {
|
if SHOW_MAPGEN_VISUALIZER {
|
||||||
let mut snapshot = self.map.clone();
|
let mut snapshot = self.map.clone();
|
||||||
@ -62,13 +81,7 @@ impl BuilderChain {
|
|||||||
BuilderChain {
|
BuilderChain {
|
||||||
starter: None,
|
starter: None,
|
||||||
builders: Vec::new(),
|
builders: Vec::new(),
|
||||||
build_data: BuilderMap {
|
build_data: BuilderMap::new(new_depth),
|
||||||
spawn_list: Vec::new(),
|
|
||||||
map: Map::new(new_depth),
|
|
||||||
starting_position: None,
|
|
||||||
rooms: None,
|
|
||||||
history: Vec::new(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,10 +168,11 @@ pub trait MapBuilder {
|
|||||||
pub fn random_builder(new_depth: i32, rng: &mut RandomNumberGenerator) -> BuilderChain {
|
pub fn random_builder(new_depth: i32, rng: &mut RandomNumberGenerator) -> BuilderChain {
|
||||||
let mut builder = BuilderChain::new(new_depth);
|
let mut builder = BuilderChain::new(new_depth);
|
||||||
builder
|
builder
|
||||||
.start_with(SimpleMapBuilder::new())
|
.start_with(CellularAutomataBuilder::new())
|
||||||
.with(RoomBasedSpawner::new())
|
.with(AreaStartingPosition::new(XStart::Center, YStart::Center))
|
||||||
.with(RoomBasedStartingPosition::new())
|
.with(CullUnreachable::new())
|
||||||
.with(RoomBasedStairs::new());
|
.with(VoronoiSpawning::new())
|
||||||
|
.with(DistantExit::new());
|
||||||
|
|
||||||
builder
|
builder
|
||||||
}
|
}
|
||||||
|
79
src/map_builders/area_starting_points.rs
Normal file
79
src/map_builders/area_starting_points.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
|
use crate::map_builders::{BuilderMap, MetaMapBuilder};
|
||||||
|
use crate::{Position, TileType};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum XStart {
|
||||||
|
Left,
|
||||||
|
Center,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum YStart {
|
||||||
|
Top,
|
||||||
|
Center,
|
||||||
|
Bottom,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AreaStartingPosition {
|
||||||
|
x: XStart,
|
||||||
|
y: YStart,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetaMapBuilder for AreaStartingPosition {
|
||||||
|
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
self.build(rng, build_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AreaStartingPosition {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(x: XStart, y: YStart) -> Box<AreaStartingPosition> {
|
||||||
|
Box::new(AreaStartingPosition { x, y })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
let seed_x = match self.x {
|
||||||
|
XStart::Left => 1,
|
||||||
|
XStart::Center => build_data.map.width / 2,
|
||||||
|
XStart::Right => build_data.map.width - 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
let seed_y = match self.y {
|
||||||
|
YStart::Top => 1,
|
||||||
|
YStart::Center => build_data.map.height / 2,
|
||||||
|
YStart::Bottom => build_data.map.height - 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut available_floors: Vec<(usize, f32)> = Vec::new();
|
||||||
|
for (idx, tiletype) in build_data.map.tiles.iter().enumerate() {
|
||||||
|
if *tiletype == TileType::Floor {
|
||||||
|
available_floors.push((
|
||||||
|
idx,
|
||||||
|
rltk::DistanceAlg::PythagorasSquared.distance2d(
|
||||||
|
rltk::Point::new(
|
||||||
|
idx as i32 % build_data.map.width,
|
||||||
|
idx as i32 / build_data.map.width,
|
||||||
|
),
|
||||||
|
rltk::Point::new(seed_x, seed_y),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if available_floors.is_empty() {
|
||||||
|
panic!("No valid floors to start on");
|
||||||
|
}
|
||||||
|
|
||||||
|
available_floors.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
||||||
|
|
||||||
|
let start_x = available_floors[0].0 as i32 % build_data.map.width;
|
||||||
|
let start_y = available_floors[0].0 as i32 / build_data.map.width;
|
||||||
|
|
||||||
|
build_data.starting_position = Some(Position {
|
||||||
|
x: start_x,
|
||||||
|
y: start_y,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,8 @@ use rltk::RandomNumberGenerator;
|
|||||||
|
|
||||||
use crate::components::Position;
|
use crate::components::Position;
|
||||||
use crate::map_builders::common::{apply_room_to_map, draw_corridor};
|
use crate::map_builders::common::{apply_room_to_map, draw_corridor};
|
||||||
use crate::{spawner, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER};
|
|
||||||
use crate::map_builders::{BuilderMap, InitialMapBuilder};
|
use crate::map_builders::{BuilderMap, InitialMapBuilder};
|
||||||
|
use crate::{spawner, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER};
|
||||||
|
|
||||||
pub struct BspDungeonBuilder {
|
pub struct BspDungeonBuilder {
|
||||||
rects: Vec<Rect>,
|
rects: Vec<Rect>,
|
||||||
@ -18,9 +18,7 @@ impl InitialMapBuilder for BspDungeonBuilder {
|
|||||||
|
|
||||||
impl BspDungeonBuilder {
|
impl BspDungeonBuilder {
|
||||||
pub fn new() -> Box<BspDungeonBuilder> {
|
pub fn new() -> Box<BspDungeonBuilder> {
|
||||||
Box::new(BspDungeonBuilder {
|
Box::new(BspDungeonBuilder { rects: Vec::new() })
|
||||||
rects: Vec::new(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
@ -28,8 +26,12 @@ impl BspDungeonBuilder {
|
|||||||
self.rects.clear();
|
self.rects.clear();
|
||||||
|
|
||||||
// Start with a single map-sized rectangle
|
// Start with a single map-sized rectangle
|
||||||
self.rects
|
self.rects.push(Rect::new(
|
||||||
.push(Rect::new(2, 2, build_data.map.width - 5, build_data.map.height - 5));
|
2,
|
||||||
|
2,
|
||||||
|
build_data.map.width - 5,
|
||||||
|
build_data.map.height - 5,
|
||||||
|
));
|
||||||
let first_room = self.rects[0];
|
let first_room = self.rects[0];
|
||||||
self.add_subrects(first_room); // Divide the first room
|
self.add_subrects(first_room); // Divide the first room
|
||||||
|
|
||||||
|
@ -2,9 +2,9 @@ use rltk::RandomNumberGenerator;
|
|||||||
|
|
||||||
use super::MapBuilder;
|
use super::MapBuilder;
|
||||||
use crate::components::Position;
|
use crate::components::Position;
|
||||||
use crate::{spawner, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER};
|
|
||||||
use crate::map_builders::{BuilderMap, InitialMapBuilder};
|
|
||||||
use crate::map_builders::common::draw_corridor;
|
use crate::map_builders::common::draw_corridor;
|
||||||
|
use crate::map_builders::{BuilderMap, InitialMapBuilder};
|
||||||
|
use crate::{spawner, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER};
|
||||||
|
|
||||||
const MIN_ROOM_SIZE: i32 = 8;
|
const MIN_ROOM_SIZE: i32 = 8;
|
||||||
|
|
||||||
@ -21,9 +21,7 @@ impl InitialMapBuilder for BspInteriorBuilder {
|
|||||||
|
|
||||||
impl BspInteriorBuilder {
|
impl BspInteriorBuilder {
|
||||||
pub fn new() -> Box<BspInteriorBuilder> {
|
pub fn new() -> Box<BspInteriorBuilder> {
|
||||||
Box::new(BspInteriorBuilder {
|
Box::new(BspInteriorBuilder { rects: Vec::new() })
|
||||||
rects: Vec::new(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
@ -31,8 +29,12 @@ impl BspInteriorBuilder {
|
|||||||
self.rects.clear();
|
self.rects.clear();
|
||||||
|
|
||||||
// Start with a single map-sized rectangle
|
// Start with a single map-sized rectangle
|
||||||
self.rects
|
self.rects.push(Rect::new(
|
||||||
.push(Rect::new(1, 1, build_data.map.width - 2, build_data.map.height - 2));
|
1,
|
||||||
|
1,
|
||||||
|
build_data.map.width - 2,
|
||||||
|
build_data.map.height - 2,
|
||||||
|
));
|
||||||
|
|
||||||
let first_room = self.rects[0];
|
let first_room = self.rects[0];
|
||||||
self.add_subrects(first_room, rng); // Divide the first room
|
self.add_subrects(first_room, rng); // Divide the first room
|
||||||
@ -45,7 +47,9 @@ impl BspInteriorBuilder {
|
|||||||
for y in room.y1..room.y2 {
|
for y in room.y1..room.y2 {
|
||||||
for x in room.x1..room.x2 {
|
for x in room.x1..room.x2 {
|
||||||
let idx = build_data.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
if idx > 0 && idx < ((build_data.map.width * build_data.map.height) - 1) as usize {
|
if idx > 0
|
||||||
|
&& idx < ((build_data.map.width * build_data.map.height) - 1) as usize
|
||||||
|
{
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,117 +2,83 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
use super::common::{
|
use crate::components::Position;
|
||||||
|
use crate::map_builders::common::{
|
||||||
generate_voronoi_spawn_regions, remove_unreachable_areas_returning_most_distant,
|
generate_voronoi_spawn_regions, remove_unreachable_areas_returning_most_distant,
|
||||||
};
|
};
|
||||||
use super::MapBuilder;
|
use crate::map_builders::{BuilderMap, InitialMapBuilder};
|
||||||
use crate::components::Position;
|
|
||||||
use crate::{spawner, Map, TileType, SHOW_MAPGEN_VISUALIZER};
|
use crate::{spawner, Map, TileType, SHOW_MAPGEN_VISUALIZER};
|
||||||
|
|
||||||
pub struct CellularAutomataBuilder {
|
pub struct CellularAutomataBuilder {}
|
||||||
map: Map,
|
|
||||||
starting_position: Position,
|
|
||||||
depth: i32,
|
|
||||||
history: Vec<Map>,
|
|
||||||
noise_areas: HashMap<i32, Vec<usize>>,
|
|
||||||
spawn_list: Vec<(usize, String)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MapBuilder for CellularAutomataBuilder {
|
impl InitialMapBuilder for CellularAutomataBuilder {
|
||||||
fn get_map(&self) -> Map {
|
#[allow(dead_code)]
|
||||||
self.map.clone()
|
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
}
|
self.build(rng, build_data);
|
||||||
|
|
||||||
fn get_starting_position(&self) -> Position {
|
|
||||||
self.starting_position
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_snapshot_history(&self) -> Vec<Map> {
|
|
||||||
self.history.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_map(&mut self) {
|
|
||||||
self.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_snapshot(&mut self) {
|
|
||||||
if SHOW_MAPGEN_VISUALIZER {
|
|
||||||
let mut snapshot = self.map.clone();
|
|
||||||
for v in snapshot.revealed_tiles.iter_mut() {
|
|
||||||
*v = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.history.push(snapshot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
|
|
||||||
&self.spawn_list
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CellularAutomataBuilder {
|
impl CellularAutomataBuilder {
|
||||||
pub fn new(new_depth: i32) -> CellularAutomataBuilder {
|
pub fn new() -> Box<CellularAutomataBuilder> {
|
||||||
CellularAutomataBuilder {
|
Box::new(CellularAutomataBuilder {})
|
||||||
map: Map::new(new_depth),
|
|
||||||
starting_position: Position::default(),
|
|
||||||
depth: new_depth,
|
|
||||||
history: Vec::new(),
|
|
||||||
noise_areas: HashMap::new(),
|
|
||||||
spawn_list: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&mut self) {
|
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
let mut rng = RandomNumberGenerator::new();
|
|
||||||
|
|
||||||
// First we completely randomize the map, setting 55% of it to be floor.
|
// First we completely randomize the map, setting 55% of it to be floor.
|
||||||
for y in 1..self.map.height - 1 {
|
for y in 1..build_data.map.height - 1 {
|
||||||
for x in 1..self.map.width - 1 {
|
for x in 1..build_data.map.width - 1 {
|
||||||
let roll = rng.roll_dice(1, 100);
|
let roll = rng.roll_dice(1, 100);
|
||||||
let idx = self.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
|
||||||
if roll > 55 {
|
if roll > 55 {
|
||||||
self.map.tiles[idx] = TileType::Floor
|
build_data.map.tiles[idx] = TileType::Floor
|
||||||
} else {
|
} else {
|
||||||
self.map.tiles[idx] = TileType::Wall
|
build_data.map.tiles[idx] = TileType::Wall
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.take_snapshot();
|
build_data.take_snapshot();
|
||||||
|
|
||||||
// Now we iteratively apply cellular automata rules
|
// Now we iteratively apply cellular automata rules
|
||||||
for _i in 0..15 {
|
for _i in 0..15 {
|
||||||
let mut newtiles = self.map.tiles.clone();
|
let mut newtiles = build_data.map.tiles.clone();
|
||||||
|
|
||||||
for y in 1..self.map.height - 1 {
|
for y in 1..build_data.map.height - 1 {
|
||||||
for x in 1..self.map.width - 1 {
|
for x in 1..build_data.map.width - 1 {
|
||||||
let idx = self.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
let mut neighbors = 0;
|
let mut neighbors = 0;
|
||||||
|
|
||||||
if self.map.tiles[idx - 1] == TileType::Wall {
|
if build_data.map.tiles[idx - 1] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if self.map.tiles[idx + 1] == TileType::Wall {
|
if build_data.map.tiles[idx + 1] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if self.map.tiles[idx - self.map.width as usize] == TileType::Wall {
|
if build_data.map.tiles[idx - build_data.map.width as usize] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if self.map.tiles[idx + self.map.width as usize] == TileType::Wall {
|
if build_data.map.tiles[idx + build_data.map.width as usize] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if self.map.tiles[idx - (self.map.width as usize - 1)] == TileType::Wall {
|
if build_data.map.tiles[idx - (build_data.map.width as usize - 1)]
|
||||||
|
== TileType::Wall
|
||||||
|
{
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if self.map.tiles[idx - (self.map.width as usize + 1)] == TileType::Wall {
|
if build_data.map.tiles[idx - (build_data.map.width as usize + 1)]
|
||||||
|
== TileType::Wall
|
||||||
|
{
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if self.map.tiles[idx + (self.map.width as usize - 1)] == TileType::Wall {
|
if build_data.map.tiles[idx + (build_data.map.width as usize - 1)]
|
||||||
|
== TileType::Wall
|
||||||
|
{
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if self.map.tiles[idx + (self.map.width as usize + 1)] == TileType::Wall {
|
if build_data.map.tiles[idx + (build_data.map.width as usize + 1)]
|
||||||
|
== TileType::Wall
|
||||||
|
{
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,45 +90,8 @@ impl CellularAutomataBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.map.tiles = newtiles.clone();
|
build_data.map.tiles = newtiles.clone();
|
||||||
self.take_snapshot();
|
build_data.take_snapshot();
|
||||||
}
|
|
||||||
|
|
||||||
// Find a starting point; start at the middle and walk left until we find an open tile
|
|
||||||
self.starting_position = Position {
|
|
||||||
x: self.map.width / 2,
|
|
||||||
y: self.map.height / 2,
|
|
||||||
};
|
|
||||||
let mut start_idx = self
|
|
||||||
.map
|
|
||||||
.xy_idx(self.starting_position.x, self.starting_position.y);
|
|
||||||
while self.map.tiles[start_idx] != TileType::Floor {
|
|
||||||
self.starting_position.x -= 1;
|
|
||||||
start_idx = self
|
|
||||||
.map
|
|
||||||
.xy_idx(self.starting_position.x, self.starting_position.y)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find all tiles we can reach from the starting point
|
|
||||||
let exit_tile = remove_unreachable_areas_returning_most_distant(&mut self.map, start_idx);
|
|
||||||
self.take_snapshot();
|
|
||||||
|
|
||||||
// Place the stairs
|
|
||||||
self.map.tiles[exit_tile] = TileType::DownStairs;
|
|
||||||
self.take_snapshot();
|
|
||||||
|
|
||||||
// Now we build a noise map for use in spawning entities later
|
|
||||||
self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng);
|
|
||||||
|
|
||||||
// Spawn the entities
|
|
||||||
for area in self.noise_areas.iter() {
|
|
||||||
spawner::spawn_region(
|
|
||||||
&self.map,
|
|
||||||
&mut rng,
|
|
||||||
area.1,
|
|
||||||
self.depth,
|
|
||||||
&mut self.spawn_list,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
46
src/map_builders/cull_unreachable.rs
Normal file
46
src/map_builders/cull_unreachable.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
|
use crate::map_builders::{BuilderMap, MetaMapBuilder};
|
||||||
|
use crate::TileType;
|
||||||
|
|
||||||
|
pub struct CullUnreachable {}
|
||||||
|
|
||||||
|
impl MetaMapBuilder for CullUnreachable {
|
||||||
|
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
self.build(rng, build_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CullUnreachable {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new() -> Box<CullUnreachable> {
|
||||||
|
Box::new(CullUnreachable {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
let starting_pos = build_data.starting_position.as_ref().unwrap().clone();
|
||||||
|
let start_idx = build_data.map.xy_idx(starting_pos.x, starting_pos.y);
|
||||||
|
|
||||||
|
build_data.map.populate_blocked();
|
||||||
|
|
||||||
|
let map_starts: Vec<usize> = vec![start_idx];
|
||||||
|
let dijkstra_map = rltk::DijkstraMap::new(
|
||||||
|
build_data.map.width as usize,
|
||||||
|
build_data.map.height as usize,
|
||||||
|
&map_starts,
|
||||||
|
&build_data.map,
|
||||||
|
1000.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
||||||
|
if *tile == TileType::Floor {
|
||||||
|
let distance_to_start = dijkstra_map.map[i];
|
||||||
|
|
||||||
|
// We can't go to this tile - so we'll make it a wall
|
||||||
|
if distance_to_start == f32::MAX {
|
||||||
|
*tile = TileType::Wall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
src/map_builders/distant_exit.rs
Normal file
55
src/map_builders/distant_exit.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
|
use crate::map_builders::{BuilderMap, MetaMapBuilder};
|
||||||
|
use crate::TileType;
|
||||||
|
|
||||||
|
pub struct DistantExit {}
|
||||||
|
|
||||||
|
impl MetaMapBuilder for DistantExit {
|
||||||
|
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
self.build(rng, build_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DistantExit {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new() -> Box<DistantExit> {
|
||||||
|
Box::new(DistantExit {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
let starting_pos = build_data.starting_position.as_ref().unwrap().clone();
|
||||||
|
let start_idx = build_data.map.xy_idx(starting_pos.x, starting_pos.y);
|
||||||
|
|
||||||
|
build_data.map.populate_blocked();
|
||||||
|
|
||||||
|
let map_starts: Vec<usize> = vec![start_idx];
|
||||||
|
let dijkstra_map = rltk::DijkstraMap::new(
|
||||||
|
build_data.map.width as usize,
|
||||||
|
build_data.map.height as usize,
|
||||||
|
&map_starts,
|
||||||
|
&build_data.map,
|
||||||
|
1000.0,
|
||||||
|
);
|
||||||
|
let mut exit_tile = (0, 0.0f32);
|
||||||
|
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
||||||
|
if *tile == TileType::Floor {
|
||||||
|
let distance_to_start = dijkstra_map.map[i];
|
||||||
|
|
||||||
|
// We can't get to this tile - so we'll make it a wall
|
||||||
|
if distance_to_start != f32::MAX {
|
||||||
|
// If it is further away than our current exit candidate, move the exit
|
||||||
|
if distance_to_start > exit_tile.1 {
|
||||||
|
exit_tile.0 = i;
|
||||||
|
exit_tile.1 = distance_to_start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place a staircase
|
||||||
|
let stairs_idx = exit_tile.0;
|
||||||
|
build_data.map.tiles[stairs_idx] = TileType::DownStairs;
|
||||||
|
build_data.take_snapshot();
|
||||||
|
}
|
||||||
|
}
|
56
src/map_builders/voronoi_spawning.rs
Normal file
56
src/map_builders/voronoi_spawning.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
|
use crate::map_builders::{BuilderMap, MetaMapBuilder};
|
||||||
|
use crate::{spawner, TileType};
|
||||||
|
|
||||||
|
pub struct VoronoiSpawning {}
|
||||||
|
|
||||||
|
impl MetaMapBuilder for VoronoiSpawning {
|
||||||
|
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
self.build(rng, build_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VoronoiSpawning {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new() -> Box<VoronoiSpawning> {
|
||||||
|
Box::new(VoronoiSpawning {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
let mut noise_areas: HashMap<i32, Vec<usize>> = HashMap::new();
|
||||||
|
let mut noise = rltk::FastNoise::seeded(rng.roll_dice(1, 65536) as u64);
|
||||||
|
noise.set_noise_type(rltk::NoiseType::Cellular);
|
||||||
|
noise.set_frequency(0.08);
|
||||||
|
noise.set_cellular_distance_function(rltk::CellularDistanceFunction::Manhattan);
|
||||||
|
|
||||||
|
for y in 1..build_data.map.height - 1 {
|
||||||
|
for x in 1..build_data.map.width - 1 {
|
||||||
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
if build_data.map.tiles[idx] == TileType::Floor {
|
||||||
|
let cell_value_f = noise.get_noise(x as f32, y as f32) * 10240.0;
|
||||||
|
let cell_value = cell_value_f as i32;
|
||||||
|
|
||||||
|
if noise_areas.contains_key(&cell_value) {
|
||||||
|
noise_areas.get_mut(&cell_value).unwrap().push(idx);
|
||||||
|
} else {
|
||||||
|
noise_areas.insert(cell_value, vec![idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn the entities
|
||||||
|
for area in noise_areas.iter() {
|
||||||
|
spawner::spawn_region(
|
||||||
|
&build_data.map,
|
||||||
|
rng,
|
||||||
|
area.1,
|
||||||
|
build_data.map.depth,
|
||||||
|
&mut build_data.spawn_list,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user