1
0
Fork 0
roguelike-game/src/map_builders/dwarf_fort.rs

127 lines
4.1 KiB
Rust

use ::rltk::{DistanceAlg, Point};
use super::{
AreaEndingPosition, AreaStartingPosition, BspCorridors, BspDungeonBuilder, BuilderChain,
BuilderMap, CorridorSpawner, CullUnreachable, DLABuilder, DistantExit, MetaMapBuilder,
RoomDrawer, RoomSort, RoomSorter, VoronoiSpawning, XEnd, XStart, YEnd, YStart,
};
use crate::{tile_walkable, TileType};
pub fn dwarf_fort_builder(new_depth: i32, width: i32, height: i32) -> BuilderChain {
let mut chain = BuilderChain::new(new_depth, width, height, "Dwarven Fortress");
chain
.start_with(BspDungeonBuilder::new())
.with(RoomSorter::new(RoomSort::Central))
.with(RoomDrawer::new())
.with(BspCorridors::new())
.with(CorridorSpawner::new())
.with(DragonsLair::new())
.with(AreaStartingPosition::new(XStart::Left, YStart::Top))
.with(CullUnreachable::new())
.with(AreaEndingPosition::new(XEnd::Right, YEnd::Bottom))
.with(VoronoiSpawning::new())
.with(DistantExit::new())
.with(DragonSpawner::new());
chain
}
pub struct DragonsLair {}
impl MetaMapBuilder for DragonsLair {
fn build_map(&mut self, build_data: &mut BuilderMap) {
self.build(build_data);
}
}
impl DragonsLair {
#[allow(dead_code)]
pub fn new() -> Box<DragonsLair> {
Box::new(DragonsLair {})
}
fn build(&mut self, build_data: &mut BuilderMap) {
build_data.map.depth = 7;
build_data.take_snapshot();
let mut builder = BuilderChain::new(6, build_data.width, build_data.height, "New Map");
builder.start_with(DLABuilder::insectoid());
builder.build_map();
// Add the history to our history
for h in builder.build_data.history.iter() {
build_data.history.push(h.clone());
}
build_data.take_snapshot();
// Merge the maps
for (idx, tt) in build_data.map.tiles.iter_mut().enumerate() {
if *tt == TileType::Wall && builder.build_data.map.tiles[idx] == TileType::Floor {
*tt = TileType::Floor;
}
}
build_data.take_snapshot();
}
}
pub struct DragonSpawner {}
impl MetaMapBuilder for DragonSpawner {
fn build_map(&mut self, build_data: &mut BuilderMap) {
self.build(build_data);
}
}
impl DragonSpawner {
#[allow(dead_code)]
pub fn new() -> Box<DragonSpawner> {
Box::new(DragonSpawner {})
}
fn build(&mut self, build_data: &mut BuilderMap) {
// Find a central location that isn't occupied
let seed_x = build_data.map.width / 2;
let seed_y = 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 tile_walkable(*tiletype) {
available_floors.push((
idx,
DistanceAlg::PythagorasSquared.distance2d(
Point::new(
idx as i32 % build_data.map.width,
idx as i32 / build_data.map.width,
),
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;
let dragon_pt = Point::new(start_x, start_y);
// Remove all spawns within 25 tiles of the drake
let w = build_data.map.width as i32;
build_data.spawn_list.retain(|spawn| {
let spawn_pt = Point::new(spawn.0 as i32 % w, spawn.0 as i32 / 2);
let distance = DistanceAlg::Pythagoras.distance2d(dragon_pt, spawn_pt);
distance > 25.0
});
// Add the dragon
let dragon_idx = build_data.map.xy_idx(start_x, start_y);
build_data
.spawn_list
.push((dragon_idx, "Black Dragon".to_string()));
}
}