swapped over to bracket-lib geometry's Rects, improved feature spawning
This commit is contained in:
parent
5a8114ec7e
commit
fcb2bd2815
15 changed files with 217 additions and 107 deletions
|
|
@ -13,7 +13,6 @@ pub mod components;
|
||||||
pub mod raws;
|
pub mod raws;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod player;
|
pub mod player;
|
||||||
pub mod rect;
|
|
||||||
pub mod gamelog;
|
pub mod gamelog;
|
||||||
pub mod gui;
|
pub mod gui;
|
||||||
pub mod map_builders;
|
pub mod map_builders;
|
||||||
|
|
@ -39,7 +38,6 @@ pub mod states;
|
||||||
|
|
||||||
pub use components::*;
|
pub use components::*;
|
||||||
use particle_system::ParticleBuilder;
|
use particle_system::ParticleBuilder;
|
||||||
pub use rect::Rect;
|
|
||||||
pub use map::*;
|
pub use map::*;
|
||||||
pub use states::runstate::RunState;
|
pub use states::runstate::RunState;
|
||||||
pub use states::state::State;
|
pub use states::state::State;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ impl BspDungeonBuilder {
|
||||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
let mut rooms: Vec<Rect> = Vec::new();
|
let mut rooms: Vec<Rect> = Vec::new();
|
||||||
self.rects.clear();
|
self.rects.clear();
|
||||||
self.rects.push(Rect::new(2, 2, build_data.map.width - 5, build_data.map.height - 5)); // Start with a single map-sized rectangle
|
self.rects.push(Rect::with_size(2, 2, build_data.map.width - 5, build_data.map.height - 5)); // Start with a single map-sized rectangle
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -49,10 +49,12 @@ impl BspDungeonBuilder {
|
||||||
let half_width = i32::max(width / 2, 1);
|
let half_width = i32::max(width / 2, 1);
|
||||||
let half_height = i32::max(height / 2, 1);
|
let half_height = i32::max(height / 2, 1);
|
||||||
|
|
||||||
self.rects.push(Rect::new(rect.x1, rect.y1, half_width, half_height));
|
self.rects.push(Rect::with_size(rect.x1, rect.y1, half_width, half_height));
|
||||||
self.rects.push(Rect::new(rect.x1, rect.y1 + half_height, half_width, half_height));
|
self.rects.push(Rect::with_size(rect.x1, rect.y1 + half_height, half_width, half_height));
|
||||||
self.rects.push(Rect::new(rect.x1 + half_width, rect.y1, half_width, half_height));
|
self.rects.push(Rect::with_size(rect.x1 + half_width, rect.y1, half_width, half_height));
|
||||||
self.rects.push(Rect::new(rect.x1 + half_width, rect.y1 + half_height, half_width, half_height));
|
self.rects.push(
|
||||||
|
Rect::with_size(rect.x1 + half_width, rect.y1 + half_height, half_width, half_height)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_random_rect(&mut self, rng: &mut RandomNumberGenerator) -> Rect {
|
fn get_random_rect(&mut self, rng: &mut RandomNumberGenerator) -> Rect {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ impl BspInteriorBuilder {
|
||||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
let mut rooms: Vec<Rect> = Vec::new();
|
let mut rooms: Vec<Rect> = Vec::new();
|
||||||
self.rects.clear();
|
self.rects.clear();
|
||||||
self.rects.push(Rect::new(1, 1, build_data.map.width - 2, build_data.map.height - 2)); // Start with a single map-sized rectangle
|
self.rects.push(Rect::with_size(1, 1, build_data.map.width - 2, build_data.map.height - 2)); // Start with a single map-sized rectangle
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -36,7 +36,10 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -50,8 +53,10 @@ impl BspInteriorBuilder {
|
||||||
let next_room = rooms[i + 1];
|
let next_room = rooms[i + 1];
|
||||||
let start_x = room.x1 + (rng.roll_dice(1, i32::abs(room.x1 - room.x2)) - 1);
|
let start_x = room.x1 + (rng.roll_dice(1, i32::abs(room.x1 - room.x2)) - 1);
|
||||||
let start_y = room.y1 + (rng.roll_dice(1, i32::abs(room.y1 - room.y2)) - 1);
|
let start_y = room.y1 + (rng.roll_dice(1, i32::abs(room.y1 - room.y2)) - 1);
|
||||||
let end_x = next_room.x1 + (rng.roll_dice(1, i32::abs(next_room.x1 - next_room.x2)) - 1);
|
let end_x =
|
||||||
let end_y = next_room.y1 + (rng.roll_dice(1, i32::abs(next_room.y1 - next_room.y2)) - 1);
|
next_room.x1 + (rng.roll_dice(1, i32::abs(next_room.x1 - next_room.x2)) - 1);
|
||||||
|
let end_y =
|
||||||
|
next_room.y1 + (rng.roll_dice(1, i32::abs(next_room.y1 - next_room.y2)) - 1);
|
||||||
draw_corridor(&mut build_data.map, start_x, start_y, end_x, end_y);
|
draw_corridor(&mut build_data.map, start_x, start_y, end_x, end_y);
|
||||||
build_data.take_snapshot();
|
build_data.take_snapshot();
|
||||||
}
|
}
|
||||||
|
|
@ -75,24 +80,24 @@ impl BspInteriorBuilder {
|
||||||
|
|
||||||
if split <= 2 {
|
if split <= 2 {
|
||||||
// Horizontal split
|
// Horizontal split
|
||||||
let h1 = Rect::new(rect.x1, rect.y1, half_width - 1, height);
|
let h1 = Rect::with_size(rect.x1, rect.y1, half_width - 1, height);
|
||||||
self.rects.push(h1);
|
self.rects.push(h1);
|
||||||
if half_width > MIN_ROOM_SIZE {
|
if half_width > MIN_ROOM_SIZE {
|
||||||
self.add_subrects(h1, rng);
|
self.add_subrects(h1, rng);
|
||||||
}
|
}
|
||||||
let h2 = Rect::new(rect.x1 + half_width, rect.y1, half_width, height);
|
let h2 = Rect::with_size(rect.x1 + half_width, rect.y1, half_width, height);
|
||||||
self.rects.push(h2);
|
self.rects.push(h2);
|
||||||
if half_width > MIN_ROOM_SIZE {
|
if half_width > MIN_ROOM_SIZE {
|
||||||
self.add_subrects(h2, rng);
|
self.add_subrects(h2, rng);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Vertical split
|
// Vertical split
|
||||||
let v1 = Rect::new(rect.x1, rect.y1, width, half_height - 1);
|
let v1 = Rect::with_size(rect.x1, rect.y1, width, half_height - 1);
|
||||||
self.rects.push(v1);
|
self.rects.push(v1);
|
||||||
if half_height > MIN_ROOM_SIZE {
|
if half_height > MIN_ROOM_SIZE {
|
||||||
self.add_subrects(v1, rng);
|
self.add_subrects(v1, rng);
|
||||||
}
|
}
|
||||||
let v2 = Rect::new(rect.x1, rect.y1 + half_height, width, half_height);
|
let v2 = Rect::with_size(rect.x1, rect.y1 + half_height, width, half_height);
|
||||||
self.rects.push(v2);
|
self.rects.push(v2);
|
||||||
if half_height > MIN_ROOM_SIZE {
|
if half_height > MIN_ROOM_SIZE {
|
||||||
self.add_subrects(v2, rng);
|
self.add_subrects(v2, rng);
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,11 @@ fn random_start_position(rng: &mut rltk::RandomNumberGenerator) -> (XStart, YSta
|
||||||
(x, y)
|
(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_room_builder(rng: &mut rltk::RandomNumberGenerator, builder: &mut BuilderChain, end: bool) {
|
fn random_room_builder(
|
||||||
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
|
builder: &mut BuilderChain,
|
||||||
|
end: bool
|
||||||
|
) {
|
||||||
let build_roll = rng.roll_dice(1, 3);
|
let build_roll = rng.roll_dice(1, 3);
|
||||||
// Start with a room builder.
|
// Start with a room builder.
|
||||||
match build_roll {
|
match build_roll {
|
||||||
|
|
@ -287,11 +291,15 @@ fn random_room_builder(rng: &mut rltk::RandomNumberGenerator, builder: &mut Buil
|
||||||
_ => builder.with(VoronoiSpawning::new()),
|
_ => builder.with(VoronoiSpawning::new()),
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.with(ThemeRooms::grass(12)); // 12% chance of an overgrown treant room.
|
builder.with(ThemeRooms::grass(5, 5 * 5)); // 5% chance of an overgrown treant room. Must be 5*5 tiles minimum.
|
||||||
builder.with(ThemeRooms::barracks(5)); // 5% chance of a squad barracks.
|
builder.with(ThemeRooms::barracks(5, 6 * 6)); // 5% chance of a squad barracks. Must be 6*6 tiles minimum.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_shape_builder(rng: &mut rltk::RandomNumberGenerator, builder: &mut BuilderChain, end: bool) -> bool {
|
fn random_shape_builder(
|
||||||
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
|
builder: &mut BuilderChain,
|
||||||
|
end: bool
|
||||||
|
) -> bool {
|
||||||
// Pick an initial builder
|
// Pick an initial builder
|
||||||
let builder_roll = rng.roll_dice(1, 16);
|
let builder_roll = rng.roll_dice(1, 16);
|
||||||
let mut want_doors = true;
|
let mut want_doors = true;
|
||||||
|
|
@ -312,7 +320,10 @@ fn random_shape_builder(rng: &mut rltk::RandomNumberGenerator, builder: &mut Bui
|
||||||
11 => builder.start_with(DLABuilder::insectoid()),
|
11 => builder.start_with(DLABuilder::insectoid()),
|
||||||
12 => builder.start_with(VoronoiBuilder::pythagoras()),
|
12 => builder.start_with(VoronoiBuilder::pythagoras()),
|
||||||
13 => builder.start_with(VoronoiBuilder::manhattan()),
|
13 => builder.start_with(VoronoiBuilder::manhattan()),
|
||||||
_ => builder.start_with(PrefabBuilder::constant(prefab_builder::prefab_levels::WFC_POPULATED)),
|
_ =>
|
||||||
|
builder.start_with(
|
||||||
|
PrefabBuilder::constant(prefab_builder::prefab_levels::WFC_POPULATED)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'Select' the centre by placing a starting position, and cull everywhere unreachable.
|
// 'Select' the centre by placing a starting position, and cull everywhere unreachable.
|
||||||
|
|
@ -333,7 +344,17 @@ fn random_shape_builder(rng: &mut rltk::RandomNumberGenerator, builder: &mut Bui
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overmap_builder() -> BuilderChain {
|
fn overmap_builder() -> BuilderChain {
|
||||||
let mut builder = BuilderChain::new(true, ID_OVERMAP, 69, 41, 0, NAME_OVERMAP, SHORTNAME_OVERMAP, 0, 1);
|
let mut builder = BuilderChain::new(
|
||||||
|
true,
|
||||||
|
ID_OVERMAP,
|
||||||
|
69,
|
||||||
|
41,
|
||||||
|
0,
|
||||||
|
NAME_OVERMAP,
|
||||||
|
SHORTNAME_OVERMAP,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
);
|
||||||
builder.start_with(PrefabBuilder::overmap());
|
builder.start_with(PrefabBuilder::overmap());
|
||||||
builder.with(Foliage::percent(TileType::Grass, 30));
|
builder.with(Foliage::percent(TileType::Grass, 30));
|
||||||
return builder;
|
return builder;
|
||||||
|
|
@ -431,7 +452,18 @@ pub fn level_builder(
|
||||||
ID_OVERMAP => overmap_builder(),
|
ID_OVERMAP => overmap_builder(),
|
||||||
ID_TOWN => town_builder(new_id, rng, width, height, 0, initial_player_level),
|
ID_TOWN => town_builder(new_id, rng, width, height, 0, initial_player_level),
|
||||||
ID_TOWN2 => forest_builder(new_id, rng, width, height, 1, initial_player_level),
|
ID_TOWN2 => forest_builder(new_id, rng, width, height, 1, initial_player_level),
|
||||||
ID_TOWN3 => random_builder(new_id, rng, width, height, 2, 1, initial_player_level, true, BuildType::Room),
|
ID_TOWN3 =>
|
||||||
|
random_builder(
|
||||||
|
new_id,
|
||||||
|
rng,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
initial_player_level,
|
||||||
|
true,
|
||||||
|
BuildType::Room
|
||||||
|
),
|
||||||
_ if new_id >= ID_INFINITE =>
|
_ if new_id >= ID_INFINITE =>
|
||||||
random_builder(
|
random_builder(
|
||||||
new_id,
|
new_id,
|
||||||
|
|
@ -444,6 +476,17 @@ pub fn level_builder(
|
||||||
false,
|
false,
|
||||||
BuildType::Room
|
BuildType::Room
|
||||||
),
|
),
|
||||||
_ => random_builder(new_id, rng, width, height, difficulty, 404, initial_player_level, false, BuildType::Room),
|
_ =>
|
||||||
|
random_builder(
|
||||||
|
new_id,
|
||||||
|
rng,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
difficulty,
|
||||||
|
404,
|
||||||
|
initial_player_level,
|
||||||
|
false,
|
||||||
|
BuildType::Room
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::prelude::*;
|
||||||
|
|
||||||
pub struct RoomBasedStairs {}
|
pub struct RoomBasedStairs {}
|
||||||
|
|
||||||
|
|
@ -17,8 +17,8 @@ impl RoomBasedStairs {
|
||||||
|
|
||||||
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
if let Some(rooms) = &build_data.rooms {
|
if let Some(rooms) = &build_data.rooms {
|
||||||
let stairs_position = rooms[rooms.len() - 1].centre();
|
let stairs_position = rooms[rooms.len() - 1].center();
|
||||||
let stairs_idx = build_data.map.xy_idx(stairs_position.0, stairs_position.1);
|
let stairs_idx = build_data.map.xy_idx(stairs_position.x, stairs_position.y);
|
||||||
build_data.map.tiles[stairs_idx] = TileType::DownStair;
|
build_data.map.tiles[stairs_idx] = TileType::DownStair;
|
||||||
build_data.take_snapshot();
|
build_data.take_snapshot();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ impl RoomBasedStartingPosition {
|
||||||
|
|
||||||
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
if let Some(rooms) = &build_data.rooms {
|
if let Some(rooms) = &build_data.rooms {
|
||||||
let start_pos = rooms[0].centre();
|
let start_pos = rooms[0].center();
|
||||||
build_data.starting_position = Some(Position { x: start_pos.0, y: start_pos.1 });
|
build_data.starting_position = Some(Position { x: start_pos.x, y: start_pos.y });
|
||||||
} else {
|
} else {
|
||||||
panic!("RoomBasedStartingPosition only works after rooms have been created");
|
panic!("RoomBasedStartingPosition only works after rooms have been created");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,20 @@ impl RoomDrawer {
|
||||||
|
|
||||||
fn circle(&mut self, build_data: &mut BuilderMap, room: &Rect) {
|
fn circle(&mut self, build_data: &mut BuilderMap, room: &Rect) {
|
||||||
let radius = (i32::min(room.x2 - room.x1, room.y2 - room.y1) as f32) / 2.0;
|
let radius = (i32::min(room.x2 - room.x1, room.y2 - room.y1) as f32) / 2.0;
|
||||||
let center = room.centre();
|
let center = room.center();
|
||||||
let center_pt = rltk::Point::new(center.0, center.1);
|
let center_pt = rltk::Point::new(center.x, center.y);
|
||||||
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);
|
||||||
let distance = rltk::DistanceAlg::Pythagoras.distance2d(center_pt, rltk::Point::new(x, y));
|
let distance = rltk::DistanceAlg::Pythagoras.distance2d(
|
||||||
if idx > 0 && idx < ((build_data.map.width * build_data.map.height - 1) as usize) && distance <= radius {
|
center_pt,
|
||||||
|
rltk::Point::new(x, y)
|
||||||
|
);
|
||||||
|
if
|
||||||
|
idx > 0 &&
|
||||||
|
idx < ((build_data.map.width * build_data.map.height - 1) as usize) &&
|
||||||
|
distance <= radius
|
||||||
|
{
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@ impl RoomExploder {
|
||||||
panic!("RoomExploder requires a builder with rooms.");
|
panic!("RoomExploder requires a builder with rooms.");
|
||||||
}
|
}
|
||||||
for room in rooms.iter() {
|
for room in rooms.iter() {
|
||||||
let start = room.centre();
|
let start = room.center();
|
||||||
let n_diggers = rng.roll_dice(1, 20) - 5;
|
let n_diggers = rng.roll_dice(1, 20) - 5;
|
||||||
if n_diggers > 0 {
|
if n_diggers > 0 {
|
||||||
for _i in 0..n_diggers {
|
for _i in 0..n_diggers {
|
||||||
let mut drunk_x = start.0;
|
let mut drunk_x = start.x;
|
||||||
let mut drunk_y = start.1;
|
let mut drunk_y = start.y;
|
||||||
let mut drunk_life = 20;
|
let mut drunk_life = 20;
|
||||||
let mut did_something = false;
|
let mut did_something = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,15 +50,24 @@ impl RoomSorter {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.sort_by(|a, b| b.y2.cmp(&a.y2)),
|
.sort_by(|a, b| b.y2.cmp(&a.y2)),
|
||||||
RoomSort::CENTRAL => {
|
RoomSort::CENTRAL => {
|
||||||
let map_centre = rltk::Point::new(build_data.map.width / 2, build_data.map.height / 2);
|
let map_centre = rltk::Point::new(
|
||||||
|
build_data.map.width / 2,
|
||||||
|
build_data.map.height / 2
|
||||||
|
);
|
||||||
build_data.rooms
|
build_data.rooms
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.sort_by(|a: &Rect, b: &Rect| {
|
.sort_by(|a: &Rect, b: &Rect| {
|
||||||
let a_centre_pt = rltk::Point::new(a.centre().0, a.centre().1);
|
let a_centre_pt = rltk::Point::new(a.center().x, a.center().y);
|
||||||
let b_centre_pt = rltk::Point::new(b.centre().0, b.centre().1);
|
let b_centre_pt = rltk::Point::new(b.center().x, b.center().y);
|
||||||
let distance_a = rltk::DistanceAlg::Pythagoras.distance2d(a_centre_pt, map_centre);
|
let distance_a = rltk::DistanceAlg::Pythagoras.distance2d(
|
||||||
let distance_b = rltk::DistanceAlg::Pythagoras.distance2d(b_centre_pt, map_centre);
|
a_centre_pt,
|
||||||
|
map_centre
|
||||||
|
);
|
||||||
|
let distance_b = rltk::DistanceAlg::Pythagoras.distance2d(
|
||||||
|
b_centre_pt,
|
||||||
|
map_centre
|
||||||
|
);
|
||||||
return distance_a.partial_cmp(&distance_b).unwrap();
|
return distance_a.partial_cmp(&distance_b).unwrap();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
use super::{ BuilderMap, MetaMapBuilder, Rect, TileType };
|
use super::{ BuilderMap, MetaMapBuilder, Rect, TileType };
|
||||||
use crate::tile_walkable;
|
use crate::tile_walkable;
|
||||||
use crate::data::messages::{ FEATURE_TREANTS, FEATURE_BARRACKS_GOBLIN, FEATURE_BARRACKS_KOBOLD, FEATURE_BARRACKS_ORC };
|
use crate::data::messages::{
|
||||||
|
FEATURE_TREANTS,
|
||||||
|
FEATURE_BARRACKS_GOBLIN,
|
||||||
|
FEATURE_BARRACKS_KOBOLD,
|
||||||
|
FEATURE_BARRACKS_ORC,
|
||||||
|
};
|
||||||
use crate::raws;
|
use crate::raws;
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
pub enum Theme {
|
pub enum Theme {
|
||||||
Grass,
|
Grass,
|
||||||
|
|
@ -12,6 +18,7 @@ pub enum Theme {
|
||||||
pub struct ThemeRooms {
|
pub struct ThemeRooms {
|
||||||
pub theme: Theme,
|
pub theme: Theme,
|
||||||
pub percent: i32,
|
pub percent: i32,
|
||||||
|
pub min_size: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetaMapBuilder for ThemeRooms {
|
impl MetaMapBuilder for ThemeRooms {
|
||||||
|
|
@ -22,24 +29,40 @@ impl MetaMapBuilder for ThemeRooms {
|
||||||
|
|
||||||
impl ThemeRooms {
|
impl ThemeRooms {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn grass(percent: i32) -> Box<ThemeRooms> {
|
pub fn grass(percent: i32, min_size: i32) -> Box<ThemeRooms> {
|
||||||
return Box::new(ThemeRooms { theme: Theme::Grass, percent });
|
return Box::new(ThemeRooms { theme: Theme::Grass, percent, min_size });
|
||||||
}
|
}
|
||||||
pub fn barracks(percent: i32) -> Box<ThemeRooms> {
|
pub fn barracks(percent: i32, min_size: i32) -> Box<ThemeRooms> {
|
||||||
return Box::new(ThemeRooms { theme: Theme::Barrack, percent });
|
return Box::new(ThemeRooms { theme: Theme::Barrack, percent, min_size });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn grassify(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap, room: &Rect) {
|
fn grassify(
|
||||||
|
&mut self,
|
||||||
|
rng: &mut RandomNumberGenerator,
|
||||||
|
build_data: &mut BuilderMap,
|
||||||
|
room: &Rect
|
||||||
|
) {
|
||||||
let (var_x, var_y) = (rng.roll_dice(1, 3), rng.roll_dice(1, 3));
|
let (var_x, var_y) = (rng.roll_dice(1, 3), rng.roll_dice(1, 3));
|
||||||
let x1 = if room.x1 - var_x > 0 { room.x1 - var_x } else { room.x1 };
|
let x1 = if room.x1 - var_x > 0 { room.x1 - var_x } else { room.x1 };
|
||||||
let x2 = if room.x2 + var_x < build_data.map.width - 1 { room.x2 + var_x } else { room.x2 };
|
let x2 = if room.x2 + var_x < build_data.map.width - 1 { room.x2 + var_x } else { room.x2 };
|
||||||
let y1 = if room.y1 - var_y > 0 { room.y1 - var_y } else { room.y1 };
|
let y1 = if room.y1 - var_y > 0 { room.y1 - var_y } else { room.y1 };
|
||||||
let y2 = if room.y2 + var_y < build_data.map.height - 1 { room.y2 + var_y } else { room.y2 };
|
let y2 = if room.y2 + var_y < build_data.map.height - 1 {
|
||||||
|
room.y2 + var_y
|
||||||
|
} else {
|
||||||
|
room.y2
|
||||||
|
};
|
||||||
for x in x1..x2 {
|
for x in x1..x2 {
|
||||||
for y in y1..y2 {
|
for y in y1..y2 {
|
||||||
let idx = build_data.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
if tile_walkable(build_data.map.tiles[idx]) && build_data.map.tiles[idx] != TileType::DownStair {
|
if
|
||||||
let tar = if x < room.x1 || x > room.x2 || y < room.y1 || y > room.y2 { 45 } else { 90 };
|
tile_walkable(build_data.map.tiles[idx]) &&
|
||||||
|
build_data.map.tiles[idx] != TileType::DownStair
|
||||||
|
{
|
||||||
|
let tar = if x < room.x1 || x > room.x2 || y < room.y1 || y > room.y2 {
|
||||||
|
45
|
||||||
|
} else {
|
||||||
|
90
|
||||||
|
};
|
||||||
let roll = rng.roll_dice(1, 100);
|
let roll = rng.roll_dice(1, 100);
|
||||||
if roll <= tar {
|
if roll <= tar {
|
||||||
match rng.roll_dice(1, 6) {
|
match rng.roll_dice(1, 6) {
|
||||||
|
|
@ -63,13 +86,21 @@ impl ThemeRooms {
|
||||||
build_data.map.messages.insert(FEATURE_TREANTS.to_string());
|
build_data.map.messages.insert(FEATURE_TREANTS.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn place_barracks(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap, room: &Rect) {
|
fn place_barracks(
|
||||||
|
&mut self,
|
||||||
|
rng: &mut RandomNumberGenerator,
|
||||||
|
build_data: &mut BuilderMap,
|
||||||
|
room: &Rect
|
||||||
|
) {
|
||||||
let mut possible: Vec<usize> = Vec::new();
|
let mut possible: Vec<usize> = Vec::new();
|
||||||
let (x1, x2, y1, y2) = (room.x1 + 1, room.x2 - 1, room.y1 + 1, room.y2 - 1);
|
let (x1, x2, y1, y2) = (room.x1 + 1, room.x2 - 1, room.y1 + 1, room.y2 - 1);
|
||||||
for x in x1..x2 {
|
for x in x1..x2 {
|
||||||
for y in y1..y2 {
|
for y in y1..y2 {
|
||||||
let idx = build_data.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
if tile_walkable(build_data.map.tiles[idx]) && build_data.map.tiles[idx] != TileType::DownStair {
|
if
|
||||||
|
tile_walkable(build_data.map.tiles[idx]) &&
|
||||||
|
build_data.map.tiles[idx] != TileType::DownStair
|
||||||
|
{
|
||||||
possible.push(idx);
|
possible.push(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,15 +144,39 @@ impl ThemeRooms {
|
||||||
panic!("RoomCornerRounding requires a builder with rooms.");
|
panic!("RoomCornerRounding requires a builder with rooms.");
|
||||||
}
|
}
|
||||||
|
|
||||||
for room in rooms.iter() {
|
let count = roll_until_fail(rng, self.percent);
|
||||||
if rng.roll_dice(1, 100) < self.percent {
|
let mut used: HashSet<usize> = HashSet::new();
|
||||||
|
|
||||||
|
for _i in 0..count {
|
||||||
|
let mut attempts = 0;
|
||||||
|
while attempts < 20 {
|
||||||
|
let room = rng.random_slice_entry(&rooms).unwrap();
|
||||||
|
let (w, h) = (room.width(), room.height());
|
||||||
|
let idx = build_data.map.xy_idx(room.x1, room.y1);
|
||||||
|
if !used.contains(&idx) && w * h >= self.min_size {
|
||||||
|
used.insert(idx);
|
||||||
match self.theme {
|
match self.theme {
|
||||||
Theme::Grass => self.grassify(rng, build_data, room),
|
Theme::Grass => self.grassify(rng, build_data, &room),
|
||||||
Theme::Barrack => self.place_barracks(rng, build_data, room),
|
Theme::Barrack => self.place_barracks(rng, build_data, &room),
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
build_data.take_snapshot();
|
build_data.take_snapshot();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
attempts += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn roll_until_fail(rng: &mut RandomNumberGenerator, target: i32) -> i32 {
|
||||||
|
let mut accumulator = 0;
|
||||||
|
loop {
|
||||||
|
if rng.roll_dice(1, 100) <= target - accumulator {
|
||||||
|
accumulator += 1;
|
||||||
|
rltk::console::log(accumulator);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,24 +29,27 @@ impl BresenhamCorridors {
|
||||||
let mut corridors: Vec<Vec<usize>> = Vec::new();
|
let mut corridors: Vec<Vec<usize>> = Vec::new();
|
||||||
for (i, room) in rooms.iter().enumerate() {
|
for (i, room) in rooms.iter().enumerate() {
|
||||||
let mut room_distance: Vec<(usize, f32)> = Vec::new();
|
let mut room_distance: Vec<(usize, f32)> = Vec::new();
|
||||||
let room_centre = room.centre();
|
let room_centre = room.center();
|
||||||
let room_centre_pt = rltk::Point::new(room_centre.0, room_centre.1);
|
let room_centre_pt = rltk::Point::new(room_centre.x, room_centre.y);
|
||||||
for (j, other_room) in rooms.iter().enumerate() {
|
for (j, other_room) in rooms.iter().enumerate() {
|
||||||
if i != j && !connected.contains(&j) {
|
if i != j && !connected.contains(&j) {
|
||||||
let other_centre = other_room.centre();
|
let other_centre = other_room.center();
|
||||||
let other_centre_pt = rltk::Point::new(other_centre.0, other_centre.1);
|
let other_centre_pt = rltk::Point::new(other_centre.x, other_centre.y);
|
||||||
let distance = rltk::DistanceAlg::Pythagoras.distance2d(room_centre_pt, other_centre_pt);
|
let distance = rltk::DistanceAlg::Pythagoras.distance2d(
|
||||||
|
room_centre_pt,
|
||||||
|
other_centre_pt
|
||||||
|
);
|
||||||
room_distance.push((j, distance));
|
room_distance.push((j, distance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !room_distance.is_empty() {
|
if !room_distance.is_empty() {
|
||||||
room_distance.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
room_distance.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
||||||
let dest_centre = rooms[room_distance[0].0].centre();
|
let dest_centre = rooms[room_distance[0].0].center();
|
||||||
let line = rltk::line2d(
|
let line = rltk::line2d(
|
||||||
rltk::LineAlg::Bresenham,
|
rltk::LineAlg::Bresenham,
|
||||||
room_centre_pt,
|
room_centre_pt,
|
||||||
rltk::Point::new(dest_centre.0, dest_centre.1)
|
rltk::Point::new(dest_centre.x, dest_centre.y)
|
||||||
);
|
);
|
||||||
let mut corridor = Vec::new();
|
let mut corridor = Vec::new();
|
||||||
for cell in line.iter() {
|
for cell in line.iter() {
|
||||||
|
|
|
||||||
|
|
@ -27,16 +27,21 @@ impl DoglegCorridors {
|
||||||
let mut corridors: Vec<Vec<usize>> = Vec::new();
|
let mut corridors: Vec<Vec<usize>> = Vec::new();
|
||||||
for (i, room) in rooms.iter().enumerate() {
|
for (i, room) in rooms.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
let (new_x, new_y) = room.centre();
|
let new = room.center();
|
||||||
let (prev_x, prev_y) = rooms[(i as usize) - 1].centre();
|
let prev = rooms[(i as usize) - 1].center();
|
||||||
if rng.range(0, 2) == 1 {
|
if rng.range(0, 2) == 1 {
|
||||||
let mut c1 = apply_horizontal_tunnel(&mut build_data.map, prev_x, new_x, prev_y);
|
let mut c1 = apply_horizontal_tunnel(
|
||||||
let mut c2 = apply_vertical_tunnel(&mut build_data.map, prev_y, new_y, new_x);
|
&mut build_data.map,
|
||||||
|
prev.x,
|
||||||
|
new.x,
|
||||||
|
prev.y
|
||||||
|
);
|
||||||
|
let mut c2 = apply_vertical_tunnel(&mut build_data.map, prev.y, new.y, new.x);
|
||||||
c1.append(&mut c2);
|
c1.append(&mut c2);
|
||||||
corridors.push(c1);
|
corridors.push(c1);
|
||||||
} else {
|
} else {
|
||||||
let mut c1 = apply_vertical_tunnel(&mut build_data.map, prev_y, new_y, prev_x);
|
let mut c1 = apply_vertical_tunnel(&mut build_data.map, prev.y, new.y, prev.x);
|
||||||
let mut c2 = apply_horizontal_tunnel(&mut build_data.map, prev_x, new_x, new_y);
|
let mut c2 = apply_horizontal_tunnel(&mut build_data.map, prev.x, new.x, new.y);
|
||||||
c1.append(&mut c2);
|
c1.append(&mut c2);
|
||||||
corridors.push(c1);
|
corridors.push(c1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,26 +29,29 @@ impl NearestCorridors {
|
||||||
let mut corridors: Vec<Vec<usize>> = Vec::new();
|
let mut corridors: Vec<Vec<usize>> = Vec::new();
|
||||||
for (i, room) in rooms.iter().enumerate() {
|
for (i, room) in rooms.iter().enumerate() {
|
||||||
let mut room_distance: Vec<(usize, f32)> = Vec::new();
|
let mut room_distance: Vec<(usize, f32)> = Vec::new();
|
||||||
let room_centre = room.centre();
|
let room_centre = room.center();
|
||||||
let room_centre_pt = rltk::Point::new(room_centre.0, room_centre.1);
|
let room_centre_pt = rltk::Point::new(room_centre.x, room_centre.y);
|
||||||
for (j, other_room) in rooms.iter().enumerate() {
|
for (j, other_room) in rooms.iter().enumerate() {
|
||||||
if i != j && !connected.contains(&j) {
|
if i != j && !connected.contains(&j) {
|
||||||
let other_centre = other_room.centre();
|
let other_centre = other_room.center();
|
||||||
let other_centre_pt = rltk::Point::new(other_centre.0, other_centre.1);
|
let other_centre_pt = rltk::Point::new(other_centre.x, other_centre.y);
|
||||||
let distance = rltk::DistanceAlg::Pythagoras.distance2d(room_centre_pt, other_centre_pt);
|
let distance = rltk::DistanceAlg::Pythagoras.distance2d(
|
||||||
|
room_centre_pt,
|
||||||
|
other_centre_pt
|
||||||
|
);
|
||||||
room_distance.push((j, distance));
|
room_distance.push((j, distance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !room_distance.is_empty() {
|
if !room_distance.is_empty() {
|
||||||
room_distance.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
room_distance.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
||||||
let dest_centre = rooms[room_distance[0].0].centre();
|
let dest_centre = rooms[room_distance[0].0].center();
|
||||||
let corridor = draw_corridor(
|
let corridor = draw_corridor(
|
||||||
&mut build_data.map,
|
&mut build_data.map,
|
||||||
room_centre.0,
|
room_centre.x,
|
||||||
room_centre.1,
|
room_centre.y,
|
||||||
dest_centre.0,
|
dest_centre.x,
|
||||||
dest_centre.1
|
dest_centre.y
|
||||||
);
|
);
|
||||||
connected.insert(i);
|
connected.insert(i);
|
||||||
build_data.take_snapshot();
|
build_data.take_snapshot();
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,11 @@ impl SimpleMapBuilder {
|
||||||
if let Some(room_params) = room_params {
|
if let Some(room_params) = room_params {
|
||||||
(max_rooms, min_size, max_size) = (room_params.0, room_params.1, room_params.2);
|
(max_rooms, min_size, max_size) = (room_params.0, room_params.1, room_params.2);
|
||||||
} else {
|
} else {
|
||||||
(max_rooms, min_size, max_size) = (DEFAULT_MAX_ROOMS, DEFAULT_MIN_SIZE, DEFAULT_MAX_SIZE);
|
(max_rooms, min_size, max_size) = (
|
||||||
|
DEFAULT_MAX_ROOMS,
|
||||||
|
DEFAULT_MIN_SIZE,
|
||||||
|
DEFAULT_MAX_SIZE,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Box::new(SimpleMapBuilder { room_params: (max_rooms, min_size, max_size) })
|
Box::new(SimpleMapBuilder { room_params: (max_rooms, min_size, max_size) })
|
||||||
|
|
@ -38,7 +42,7 @@ impl SimpleMapBuilder {
|
||||||
let h = rng.range(self.room_params.1, self.room_params.2);
|
let h = rng.range(self.room_params.1, self.room_params.2);
|
||||||
let x = rng.roll_dice(1, build_data.map.width - w - 1) - 1;
|
let x = rng.roll_dice(1, build_data.map.width - w - 1) - 1;
|
||||||
let y = rng.roll_dice(1, build_data.map.height - h - 1) - 1;
|
let y = rng.roll_dice(1, build_data.map.height - h - 1) - 1;
|
||||||
let new_room = Rect::new(x, y, w, h);
|
let new_room = Rect::with_size(x, y, w, h);
|
||||||
let mut ok = true;
|
let mut ok = true;
|
||||||
for other_room in rooms.iter() {
|
for other_room in rooms.iter() {
|
||||||
if new_room.intersect(other_room) {
|
if new_room.intersect(other_room) {
|
||||||
|
|
|
||||||
24
src/rect.rs
24
src/rect.rs
|
|
@ -1,24 +0,0 @@
|
||||||
use serde::{ Deserialize, Serialize };
|
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Rect {
|
|
||||||
pub x1: i32,
|
|
||||||
pub x2: i32,
|
|
||||||
pub y1: i32,
|
|
||||||
pub y2: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rect {
|
|
||||||
pub fn new(x: i32, y: i32, w: i32, h: i32) -> Rect {
|
|
||||||
Rect { x1: x, y1: y, x2: x + w, y2: y + h }
|
|
||||||
}
|
|
||||||
|
|
||||||
//Returns true if this overlaps with other
|
|
||||||
pub fn intersect(&self, other: &Rect) -> bool {
|
|
||||||
self.x1 <= other.x2 && self.x2 >= other.x1 && self.y1 <= other.y2 && self.y2 >= other.y1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn centre(&self) -> (i32, i32) {
|
|
||||||
((self.x1 + self.x2) / 2, (self.y1 + self.y2) / 2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue