Hunt-and-kill algorithm rocks. It handles everything I need for map gen, including spawn points, room placement, and the maze like map.
This commit is contained in:
parent
0f8e61797f
commit
a0b785cb2a
8 changed files with 62 additions and 336 deletions
4
Makefile
4
Makefile
|
@ -26,7 +26,7 @@ tracy_build:
|
||||||
meson compile -j 10 -C builddir
|
meson compile -j 10 -C builddir
|
||||||
|
|
||||||
test: build
|
test: build
|
||||||
./builddir/runtests "[maze-gen]"
|
./builddir/runtests "[levelmanager]"
|
||||||
|
|
||||||
run: build test
|
run: build test
|
||||||
ifeq '$(OS)' 'Windows_NT'
|
ifeq '$(OS)' 'Windows_NT'
|
||||||
|
@ -49,7 +49,7 @@ clean:
|
||||||
meson compile --clean -C builddir
|
meson compile --clean -C builddir
|
||||||
|
|
||||||
debug_test: build
|
debug_test: build
|
||||||
gdb --nx -x .gdbinit --ex run --args builddir/runtests -e "[maze-gen]"
|
gdb --nx -x .gdbinit --ex run --args builddir/runtests -e "[levelmanager]"
|
||||||
|
|
||||||
win_installer:
|
win_installer:
|
||||||
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp'
|
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp'
|
||||||
|
|
|
@ -354,7 +354,7 @@ namespace gui {
|
||||||
if($map_open) {
|
if($map_open) {
|
||||||
$map_ui.render($window, $main_ui.$compass_dir);
|
$map_ui.render($window, $main_ui.$compass_dir);
|
||||||
} else {
|
} else {
|
||||||
$mini_map.render($window, $main_ui.$compass_dir);
|
// $mini_map.render($window, $main_ui.$compass_dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
175
maze.cpp
175
maze.cpp
|
@ -18,134 +18,7 @@ inline size_t rand(size_t i, size_t j) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool split_dir(size_t iDim, size_t jDim) {
|
inline bool complete(Matrix& maze) {
|
||||||
if(iDim < jDim) {
|
|
||||||
return false;
|
|
||||||
} else if(jDim < iDim) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return Random::uniform(0, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool good_hole(Matrix &map, size_t split, size_t hole, bool horiz) {
|
|
||||||
if(hole % 2 == 0) return false;
|
|
||||||
|
|
||||||
size_t j = horiz ? split : hole;
|
|
||||||
size_t i = horiz ? hole : split;
|
|
||||||
if(map[j][i] == WALL_PATH_LIMIT) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void divide(Matrix& map, std::vector<Room> &rooms,
|
|
||||||
Point iCoords, Point jCoords, bool horizontal) {
|
|
||||||
int iDim = iCoords.y - iCoords.x;
|
|
||||||
int jDim = jCoords.y - jCoords.x;
|
|
||||||
bool punch_room = false;
|
|
||||||
|
|
||||||
if(iDim <= 0 || jDim <= 0) {
|
|
||||||
return;
|
|
||||||
} else if(iDim <= 2 && jDim <= 2) {
|
|
||||||
fmt::println("MADE ROOM! {},{}; {},{}",
|
|
||||||
iCoords.x, iCoords.y, jCoords.x, jCoords.y);
|
|
||||||
punch_room = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(horizontal) {
|
|
||||||
size_t split = 0;
|
|
||||||
do {
|
|
||||||
split = rand(iCoords.x, iCoords.x + iDim + 1);
|
|
||||||
} while(split % 2);
|
|
||||||
|
|
||||||
size_t hole = 0;
|
|
||||||
do {
|
|
||||||
hole = rand(jCoords.x, jCoords.x + jDim +1);
|
|
||||||
} while(good_hole(map, split, hole, horizontal));
|
|
||||||
|
|
||||||
for(size_t j = jCoords.x; j <= jCoords.y; j++) {
|
|
||||||
if(j != hole) {
|
|
||||||
map[split][j] = WALL_PATH_LIMIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
divide(map, rooms,
|
|
||||||
{iCoords.x, size_t(split - 1)},
|
|
||||||
jCoords,
|
|
||||||
split_dir(split - iCoords.x - 1, jDim));
|
|
||||||
|
|
||||||
divide(map, rooms,
|
|
||||||
{size_t(split + 1), iCoords.y},
|
|
||||||
jCoords,
|
|
||||||
split_dir(iCoords.x - split - 1, jDim));
|
|
||||||
} else {
|
|
||||||
size_t split = 0;
|
|
||||||
do {
|
|
||||||
split = rand(jCoords.x, jCoords.x + jDim + 1);
|
|
||||||
} while(split % 2);
|
|
||||||
|
|
||||||
size_t hole = 0;
|
|
||||||
do {
|
|
||||||
hole = rand(iCoords.x, iCoords.x + iDim + 1);
|
|
||||||
} while(good_hole(map, split, hole, horizontal));
|
|
||||||
|
|
||||||
for(size_t i = iCoords.x; i <= iCoords.y; i++) {
|
|
||||||
if(i != hole) {
|
|
||||||
map[i][split] = WALL_PATH_LIMIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
divide(map, rooms,
|
|
||||||
iCoords,
|
|
||||||
{jCoords.x, size_t(split - 1)},
|
|
||||||
split_dir(iDim, split - jCoords.x - 1));
|
|
||||||
|
|
||||||
divide(map, rooms,
|
|
||||||
iCoords,
|
|
||||||
{size_t(split + 1), jCoords.y},
|
|
||||||
Random::uniform(0, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(punch_room) {
|
|
||||||
// for(size_t j = jCoords.x; j <= jCoords.y; j++) {
|
|
||||||
// for(size_t i = iCoords.x; i <= iCoords.y; i++) {
|
|
||||||
// map[j][i] = 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
Room room{iCoords.x, jCoords.x, iCoords.y - iCoords.x + 1, jCoords.y - jCoords.x + 1};
|
|
||||||
|
|
||||||
for(auto r : rooms) {
|
|
||||||
if(r.x == room.x && r.y == room.y) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rooms.push_back(room);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void maze::recursive_div(Matrix& map, std::vector<Room>& rooms) {
|
|
||||||
size_t width = matrix::width(map);
|
|
||||||
size_t height = matrix::height(map);
|
|
||||||
|
|
||||||
for(size_t i = 0; i < height; i++) {
|
|
||||||
for(size_t j = 0; j < width; j++) {
|
|
||||||
int val = (i == 0 ||
|
|
||||||
j == 0 ||
|
|
||||||
i == height - 1 ||
|
|
||||||
j == width - 1);
|
|
||||||
|
|
||||||
map[i][j] = val == 1 ? WALL_PATH_LIMIT : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
divide(map, rooms, {1, height - 2}, {1, width - 2}, split_dir(1, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool complete(Matrix& maze) {
|
|
||||||
size_t width = matrix::width(maze);
|
size_t width = matrix::width(maze);
|
||||||
size_t height = matrix::height(maze);
|
size_t height = matrix::height(maze);
|
||||||
|
|
||||||
|
@ -190,7 +63,7 @@ std::vector<Point> neighbors(Matrix& maze, Point on) {
|
||||||
|
|
||||||
for(auto point : points) {
|
for(auto point : points) {
|
||||||
if(matrix::inbounds(maze, point.x, point.y)) {
|
if(matrix::inbounds(maze, point.x, point.y)) {
|
||||||
if(maze[point.y][point.x] == WALL_PATH_LIMIT) {
|
if(maze[point.y][point.x] == WALL_VALUE) {
|
||||||
result.push_back(point);
|
result.push_back(point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,13 +72,13 @@ std::vector<Point> neighbors(Matrix& maze, Point on) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<Point, Point> findCoord(Matrix& maze) {
|
inline std::pair<Point, Point> find_coord(Matrix& maze) {
|
||||||
size_t width = matrix::width(maze);
|
size_t width = matrix::width(maze);
|
||||||
size_t height = matrix::height(maze);
|
size_t height = matrix::height(maze);
|
||||||
|
|
||||||
for(size_t y = 1; y < height; y += 2) {
|
for(size_t y = 1; y < height; y += 2) {
|
||||||
for(size_t x = 1; x < width; x += 2) {
|
for(size_t x = 1; x < width; x += 2) {
|
||||||
if(maze[y][x] == WALL_PATH_LIMIT) {
|
if(maze[y][x] == WALL_VALUE) {
|
||||||
auto found = neighborsAB(maze, {x, y});
|
auto found = neighborsAB(maze, {x, y});
|
||||||
|
|
||||||
for(auto point : found) {
|
for(auto point : found) {
|
||||||
|
@ -221,34 +94,35 @@ std::pair<Point, Point> findCoord(Matrix& maze) {
|
||||||
dbc::sentinel("failed to find coord?");
|
dbc::sentinel("failed to find coord?");
|
||||||
}
|
}
|
||||||
|
|
||||||
void maze::hunt_and_kill(Matrix& maze, std::vector<Room>& rooms) {
|
void maze::hunt_and_kill(Matrix& maze, std::vector<Room>& rooms, std::vector<Point>& dead_ends) {
|
||||||
size_t width = matrix::width(maze);
|
matrix::assign(maze, WALL_VALUE);
|
||||||
size_t height = matrix::height(maze);
|
|
||||||
matrix::assign(maze, WALL_PATH_LIMIT);
|
|
||||||
|
|
||||||
Room start{2, 2, 3, 3};
|
Point last_even{0,0};
|
||||||
rooms.push_back(start);
|
|
||||||
Room goal{width-4, height-4, 3, 3};
|
|
||||||
rooms.push_back(goal);
|
|
||||||
|
|
||||||
for(auto& room : rooms) {
|
for(auto& room : rooms) {
|
||||||
for(matrix::box it{maze, room.x, room.y, 1}; it.next();) {
|
if(room.x % 2 == 0 && room.y % 2 == 0) {
|
||||||
|
last_even = {room.x, room.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
for(matrix::box it{maze, room.x, room.y, room.width}; it.next();) {
|
||||||
maze[it.y][it.x] = 0;
|
maze[it.y][it.x] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Point on{1,1};
|
Point on{1,1};
|
||||||
|
|
||||||
while(!complete(maze)) {
|
while(!complete(maze)) {
|
||||||
auto n = neighbors(maze, on);
|
auto n = neighbors(maze, on);
|
||||||
if(n.size() == 0) {
|
if(n.size() == 0) {
|
||||||
auto t = findCoord(maze);
|
dead_ends.push_back(on);
|
||||||
|
auto t = find_coord(maze);
|
||||||
on = t.first;
|
on = t.first;
|
||||||
maze[on.y][on.x] = 0;
|
maze[on.y][on.x] = 0;
|
||||||
size_t row = (on.y + t.second.y) / 2;
|
size_t row = (on.y + t.second.y) / 2;
|
||||||
size_t col = (on.x + t.second.x) / 2;
|
size_t col = (on.x + t.second.x) / 2;
|
||||||
maze[row][col] = 0;
|
maze[row][col] = 0;
|
||||||
} else {
|
} else {
|
||||||
auto nb = n[Random::uniform(size_t(0), n.size() - 1)];
|
auto nb = n[rand(size_t(0), n.size() - 1)];
|
||||||
maze[nb.y][nb.x] = 0;
|
maze[nb.y][nb.x] = 0;
|
||||||
|
|
||||||
size_t row = (nb.y + on.y) / 2;
|
size_t row = (nb.y + on.y) / 2;
|
||||||
|
@ -257,4 +131,21 @@ void maze::hunt_and_kill(Matrix& maze, std::vector<Room>& rooms) {
|
||||||
on = nb;
|
on = nb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(auto at : dead_ends) {
|
||||||
|
for(auto& room : rooms) {
|
||||||
|
Point room_ul{room.x - room.width - 1, room.y - room.height - 1};
|
||||||
|
Point room_lr{room.x + room.width - 1, room.y + room.height - 1};
|
||||||
|
if(at.x >= room_ul.x && at.y >= room_ul.y &&
|
||||||
|
at.x <= room_lr.x && at.y <= room_lr.y)
|
||||||
|
{
|
||||||
|
for(matrix::compass it{maze, at.x, at.y}; it.next();) {
|
||||||
|
if(maze[it.y][it.x] == 1) {
|
||||||
|
maze[it.y][it.x] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
4
maze.hpp
4
maze.hpp
|
@ -3,7 +3,5 @@
|
||||||
#include "map.hpp"
|
#include "map.hpp"
|
||||||
|
|
||||||
namespace maze {
|
namespace maze {
|
||||||
void recursive_div(matrix::Matrix& map, std::vector<Room>& rooms);
|
void hunt_and_kill(Matrix& maze, std::vector<Room>& rooms, std::vector<Point>& dead_ends);
|
||||||
|
|
||||||
void hunt_and_kill(Matrix& maze, std::vector<Room>& rooms);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,16 @@ union ColorConv {
|
||||||
uint32_t as_int;
|
uint32_t as_int;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline uint32_t old_lighting(uint32_t pixel, float dist, int level) {
|
||||||
|
(void)level;
|
||||||
|
ColorConv conv{.as_int=pixel};
|
||||||
|
conv.as_color.r /= dist;
|
||||||
|
conv.as_color.g /= dist;
|
||||||
|
conv.as_color.b /= dist;
|
||||||
|
|
||||||
|
return conv.as_int;
|
||||||
|
}
|
||||||
|
|
||||||
/* It's hard to believe, but this is faster than any bitfiddling
|
/* It's hard to believe, but this is faster than any bitfiddling
|
||||||
* I could devise. Just use a union with a struct, do the math
|
* I could devise. Just use a union with a struct, do the math
|
||||||
* and I guess the compiler can handle it better than shifting
|
* and I guess the compiler can handle it better than shifting
|
||||||
|
|
|
@ -10,24 +10,12 @@ using std::string;
|
||||||
using matrix::Matrix;
|
using matrix::Matrix;
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("recursive division (garbage)", "[mazes]") {
|
|
||||||
auto map = matrix::make(21, 21);
|
|
||||||
std::vector<Room> rooms;
|
|
||||||
|
|
||||||
maze::recursive_div(map, rooms);
|
|
||||||
matrix::dump("MAZE?", map);
|
|
||||||
|
|
||||||
for(auto& room : rooms) {
|
|
||||||
fmt::println("room: {},{}; {},{}",
|
|
||||||
room.x, room.y, room.width, room.height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("hunt-and-kill", "[maze-gen]") {
|
TEST_CASE("hunt-and-kill", "[maze-gen]") {
|
||||||
auto map = matrix::make(21, 21);
|
auto map = matrix::make(21, 21);
|
||||||
std::vector<Room> rooms;
|
std::vector<Room> rooms;
|
||||||
|
std::vector<Point> dead_ends;
|
||||||
|
|
||||||
maze::hunt_and_kill(map, rooms);
|
maze::hunt_and_kill(map, rooms, dead_ends);
|
||||||
matrix::dump("MAZE?", map);
|
matrix::dump("MAZE?", map);
|
||||||
|
|
||||||
for(auto& room : rooms) {
|
for(auto& room : rooms) {
|
||||||
|
|
179
worldbuilder.cpp
179
worldbuilder.cpp
|
@ -18,11 +18,6 @@ inline int make_split(Room &cur, bool horiz) {
|
||||||
return Random::uniform<int>(min, max);
|
return Random::uniform<int>(min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldBuilder::set_door(Room &room, int value) {
|
|
||||||
$map.$walls[room.entry.y][room.entry.x] = value;
|
|
||||||
$map.$walls[room.exit.y][room.exit.x] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rand_side(Room &room, Point &door) {
|
void rand_side(Room &room, Point &door) {
|
||||||
dbc::check(int(room.width) > 0 && int(room.height) > 0, "Weird room with 0 for height or width.");
|
dbc::check(int(room.width) > 0 && int(room.height) > 0, "Weird room with 0 for height or width.");
|
||||||
int rand_x = Random::uniform<int>(0, room.width - 1);
|
int rand_x = Random::uniform<int>(0, room.width - 1);
|
||||||
|
@ -55,101 +50,22 @@ void WorldBuilder::add_door(Room &room) {
|
||||||
rand_side(room, room.exit);
|
rand_side(room, room.exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldBuilder::partition_map(Room &cur, int depth) {
|
|
||||||
if(cur.width >= 3 && cur.width <= 6 &&
|
|
||||||
cur.height >= 3 && cur.height <= 6)
|
|
||||||
{
|
|
||||||
$map.add_room(cur);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool horiz = cur.width > cur.height ? false : true;
|
|
||||||
int split = make_split(cur, horiz);
|
|
||||||
if(split <= 0) return; // end recursion
|
|
||||||
|
|
||||||
Room left = cur;
|
|
||||||
Room right = cur;
|
|
||||||
|
|
||||||
if(horiz) {
|
|
||||||
if(split >= int(cur.height)) return; // end recursion
|
|
||||||
|
|
||||||
left.height = size_t(split - 1);
|
|
||||||
right.y = cur.y + split;
|
|
||||||
right.height = size_t(cur.height - split);
|
|
||||||
} else {
|
|
||||||
if(split >= int(cur.width)) return; // end recursion
|
|
||||||
|
|
||||||
left.width = size_t(split-1);
|
|
||||||
right.x = cur.x + split,
|
|
||||||
right.width = size_t(cur.width - split);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BUG: min room size should be configurable
|
|
||||||
if(depth > 0 && left.width > 2 && left.height > 2) {
|
|
||||||
partition_map(left, depth-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BUG: min room size should be configurable
|
|
||||||
if(depth > 0 && right.width > 2 && right.height > 2) {
|
|
||||||
partition_map(right, depth-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldBuilder::update_door(Point &at, int wall_or_space) {
|
|
||||||
$map.$walls[at.y][at.x] = wall_or_space;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void WorldBuilder::stylize_room(int room, string tile_name, float size) {
|
|
||||||
Point pos_out;
|
|
||||||
bool placed = $map.place_entity(room, pos_out);
|
|
||||||
dbc::check(placed, "failed to place style in room");
|
|
||||||
(void)tile_name;
|
|
||||||
(void)size;
|
|
||||||
|
|
||||||
//tile_name = tile_name == "FLOOR_TILE" ? "WALL_PLAIN" : tile_name;
|
|
||||||
|
|
||||||
//for(matrix::circle it{$map.$walls, pos_out, size}; it.next();) {
|
|
||||||
// for(int x = it.left; x < it.right; x++) {
|
|
||||||
// if($map.iswall(x, it.y)) {
|
|
||||||
// // a wall tile
|
|
||||||
// $map.$tiles.set_tile(x, it.y, tile_name);
|
|
||||||
// } else {
|
|
||||||
// // a floor tile
|
|
||||||
// $map.$tiles.set_tile(x, it.y, "FLOOR_TILE");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldBuilder::generate_rooms() {
|
|
||||||
Room root{
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
.width = $map.$width,
|
|
||||||
.height = $map.$height
|
|
||||||
};
|
|
||||||
// BUG: depth should be configurable
|
|
||||||
partition_map(root, 10);
|
|
||||||
place_rooms();
|
|
||||||
|
|
||||||
dbc::check($map.room_count() > 0, "map generated zero rooms, map too small?");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldBuilder::generate_map() {
|
void WorldBuilder::generate_map() {
|
||||||
maze::hunt_and_kill($map.$walls, $map.$rooms);
|
std::vector<Point> dead_ends;
|
||||||
|
maze::hunt_and_kill($map.$walls, $map.$rooms, dead_ends);
|
||||||
|
|
||||||
|
for(auto at : dead_ends) {
|
||||||
|
if(Random::uniform(0,1)) {
|
||||||
|
Room cur{at.x, at.y, 2, 2};
|
||||||
|
add_door(cur);
|
||||||
|
$map.add_room(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
maze::hunt_and_kill($map.$walls, $map.$rooms, dead_ends);
|
||||||
|
|
||||||
$map.expand();
|
$map.expand();
|
||||||
$map.load_tiles();
|
$map.load_tiles();
|
||||||
|
|
||||||
// get only the tiles with no collision to fill rooms
|
|
||||||
auto room_types = $map.$tiles.tile_names(false);
|
|
||||||
|
|
||||||
for(size_t i = 0; i < $map.$rooms.size() - 1; i++) {
|
|
||||||
size_t room_type = Random::uniform<size_t>(0, room_types.size() - 1);
|
|
||||||
int room_size = Random::uniform<int>(100, 800);
|
|
||||||
string tile_name = room_types[room_type];
|
|
||||||
stylize_room(i, tile_name, room_size * 0.01f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -260,72 +176,3 @@ void WorldBuilder::generate(DinkyECS::World &world) {
|
||||||
generate_map();
|
generate_map();
|
||||||
place_entities(world);
|
place_entities(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldBuilder::make_room(size_t origin_x, size_t origin_y, size_t w, size_t h) {
|
|
||||||
$map.INVARIANT();
|
|
||||||
dbc::pre("y out of bounds", origin_y + h < $map.$height);
|
|
||||||
dbc::pre("x out of bounds", origin_x + w < $map.$width);
|
|
||||||
|
|
||||||
for(size_t y = origin_y; y < origin_y + h; ++y) {
|
|
||||||
for(size_t x = origin_x; x < origin_x + w; ++x) {
|
|
||||||
$map.$walls[y][x] = INV_SPACE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void WorldBuilder::place_rooms() {
|
|
||||||
for(auto &cur : $map.$rooms) {
|
|
||||||
add_door(cur);
|
|
||||||
make_room(cur.x, cur.y, cur.width, cur.height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool random_path(Map &map, PointList &holes, Point src, Point target) {
|
|
||||||
bool keep_going = false;
|
|
||||||
bool target_found = false;
|
|
||||||
int count = 0;
|
|
||||||
map.set_target(target);
|
|
||||||
map.make_paths();
|
|
||||||
Matrix &paths = map.paths();
|
|
||||||
|
|
||||||
Point out{src.x, src.y};
|
|
||||||
do {
|
|
||||||
keep_going = map.neighbors(out, true);
|
|
||||||
holes.push_back(out);
|
|
||||||
target_found = paths[out.y][out.x] == 0;
|
|
||||||
} while(!target_found && keep_going && ++count < WORLDBUILD_MAX_PATH);
|
|
||||||
|
|
||||||
map.INVARIANT();
|
|
||||||
map.clear_target(target);
|
|
||||||
|
|
||||||
return target_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void straight_path(Map &map, PointList &holes, Point src, Point target) {
|
|
||||||
for(matrix::line dig{src, target}; dig.next();) {
|
|
||||||
holes.emplace_back(size_t(dig.x), size_t(dig.y));
|
|
||||||
Point expand{(size_t)dig.x+1, (size_t)dig.y};
|
|
||||||
|
|
||||||
if(map.inmap(expand.x, expand.y)) {
|
|
||||||
// BUG? should really just move doors away from the edge
|
|
||||||
holes.push_back(expand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldBuilder::tunnel_doors(PointList &holes, Room &src, Room &target) {
|
|
||||||
int path_type = Random::uniform<int>(0, 10);
|
|
||||||
|
|
||||||
switch(path_type) {
|
|
||||||
case 0:
|
|
||||||
// then do the rest as random with fallback
|
|
||||||
if(!random_path($map, holes, src.exit, target.entry)) {
|
|
||||||
straight_path($map, holes, src.exit, target.entry);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// for now do 25% as simple straight paths
|
|
||||||
straight_path($map, holes, src.exit, target.entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,15 +14,7 @@ class WorldBuilder {
|
||||||
$components(components)
|
$components(components)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void partition_map(Room &cur, int depth);
|
|
||||||
void make_room(size_t origin_y, size_t origin_x, size_t width, size_t height);
|
|
||||||
void add_door(Room &room);
|
void add_door(Room &room);
|
||||||
void set_door(Room &room, int value);
|
|
||||||
void place_rooms();
|
|
||||||
void tunnel_doors(PointList &holes, Room &src, Room &target);
|
|
||||||
void update_door(Point &at, int wall_or_space);
|
|
||||||
void stylize_room(int room, std::string tile_name, float size);
|
|
||||||
void generate_rooms();
|
|
||||||
void generate_map();
|
void generate_map();
|
||||||
|
|
||||||
DinkyECS::Entity configure_entity_in_map(DinkyECS::World &world, nlohmann::json &entity_data, int in_room);
|
DinkyECS::Entity configure_entity_in_map(DinkyECS::World &world, nlohmann::json &entity_data, int in_room);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue