diff --git a/Makefile b/Makefile index 6b74d7b..06a95fc 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ tracy_build: meson compile -j 10 -C builddir test: build - ./builddir/runtests + ./builddir/runtests "[mazes]" run: build test ifeq '$(OS)' 'Windows_NT' @@ -49,7 +49,7 @@ clean: meson compile --clean -C builddir debug_test: build - gdb --nx -x .gdbinit --ex run --args builddir/runtests -e + gdb --nx -x .gdbinit --ex run --args builddir/runtests -e "[mazes]" win_installer: powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp' diff --git a/assets/config.json b/assets/config.json index ab36b4d..f551488 100644 --- a/assets/config.json +++ b/assets/config.json @@ -100,6 +100,11 @@ "frame_width": 256, "frame_height": 256 }, + "lava_floor": + {"path": "assets/lava_floor-256.png", + "frame_width": 256, + "frame_height": 256 + }, "ceiling": {"path": "assets/ceiling_test-256.png", "frame_width": 256, diff --git a/assets/lava_floor-256.png b/assets/lava_floor-256.png new file mode 100644 index 0000000..2a09974 Binary files /dev/null and b/assets/lava_floor-256.png differ diff --git a/map.cpp b/map.cpp index 6f3f7d1..2474531 100644 --- a/map.cpp +++ b/map.cpp @@ -165,21 +165,6 @@ void Map::expand() { } void Map::add_room(Room &room) { - room.x++; - room.y++; - room.width--; - room.height--; - - if(room.x + room.width >= $width) { - // fix the width - room.x--; - } - - if(room.y + room.height >= $height) { - // fix the height - room.y--; - } - $rooms.push_back(room); } diff --git a/maze.cpp b/maze.cpp index 4b785c7..a45c8c2 100644 --- a/maze.cpp +++ b/maze.cpp @@ -93,16 +93,39 @@ inline std::pair find_coord(Matrix& maze) { dbc::sentinel("failed to find coord?"); } -void maze::hunt_and_kill(Matrix& maze, std::vector& rooms, std::vector& dead_ends) { +void maze::randomize_rooms(std::vector& rooms_out, std::vector maybe_here) { + dbc::check(maybe_here.size() >= 2, "must have at least two possible points to place rooms"); + + while(rooms_out.size() < 2) { + // use those dead ends to randomly place rooms + for(auto at : maybe_here) { + if(Random::uniform(0,1)) { + size_t offset = Random::uniform(0,1); + Room cur{at.x+offset, at.y+offset, 1, 1}; + rooms_out.push_back(cur); + } + } + } +} + +void maze::init(Matrix& maze) { matrix::assign(maze, WALL_VALUE); +} + +void maze::divide(Matrix& maze, Point start, Point end) { + for(matrix::line it{start, end}; it.next();) { + maze[it.y][it.x] = 0; + maze[it.y+1][it.x] = 0; + } +} - Point last_even{0,0}; +void maze::hunt_and_kill(Matrix& maze, std::vector& rooms, std::vector& dead_ends, bool init_map) { - for(auto& room : rooms) { - if(room.x % 2 == 0 && room.y % 2 == 0) { - last_even = {room.x, room.y}; - } + if(init_map) { + maze::init(maze); + } + for(auto& room : rooms) { for(matrix::box it{maze, room.x, room.y, room.width}; it.next();) { maze[it.y][it.x] = 0; } @@ -149,3 +172,34 @@ void maze::hunt_and_kill(Matrix& maze, std::vector& rooms, std::vector& dead_ends) { + for(auto at : dead_ends) { + for(matrix::compass it{maze, at.x, at.y}; it.next();) { + if(maze[it.y][it.x] == 0) { + int diff_x = at.x - it.x; + int diff_y = at.y - it.y; + maze[at.y + diff_y][at.x + diff_x] = 0; + } + } + } +} diff --git a/maze.hpp b/maze.hpp index bf4f3c7..40307ce 100644 --- a/maze.hpp +++ b/maze.hpp @@ -3,5 +3,16 @@ #include "map.hpp" namespace maze { - void hunt_and_kill(Matrix& maze, std::vector& rooms, std::vector& dead_ends); + + void init(Matrix& maze); + + void hunt_and_kill(Matrix& maze, std::vector& rooms, std::vector& dead_ends, bool init_map=true); + + void randomize_rooms(std::vector& rooms_out, std::vector maybe_here); + + void inner_ring(Matrix& map, size_t outer_size, size_t inner_size); + + void divide(Matrix& maze, Point start, Point end); + + void remove_dead_ends(Matrix& maze, std::vector& dead_ends); } diff --git a/tests/mazes.cpp b/tests/mazes.cpp index df5314d..f956723 100644 --- a/tests/mazes.cpp +++ b/tests/mazes.cpp @@ -10,16 +10,94 @@ using std::string; using matrix::Matrix; -TEST_CASE("hunt-and-kill", "[maze-gen]") { +TEST_CASE("hunt-and-kill", "[mazes]") { auto map = matrix::make(21, 21); std::vector rooms; std::vector dead_ends; maze::hunt_and_kill(map, rooms, dead_ends); - matrix::dump("MAZE?", map); + matrix::dump("BASIC MAZE", map); + + maze::randomize_rooms(rooms, dead_ends); + maze::hunt_and_kill(map, rooms, dead_ends); for(auto& room : rooms) { - fmt::println("room: {},{}; {},{}", - room.x, room.y, room.width, room.height); + for(matrix::box it{map, room.x, room.y, room.width}; + it.next();) + { + map[it.y][it.x] = WALL_PATH_LIMIT; + } + } + + matrix::dump("MAZE WITH ROOMS", map); +} + +TEST_CASE("hunt-and-kill ring", "[mazes]") { + auto map = matrix::make(21, 21); + std::vector rooms; + std::vector dead_ends; + + maze::init(map); + maze::inner_ring(map, 5, 2); + maze::hunt_and_kill(map, rooms, dead_ends, false); + + for(auto at : dead_ends) { + map[at.y][at.x]=32; } + matrix::dump("RING MAZE", map); + + REQUIRE(rooms.size() == 0); +} + +TEST_CASE("hunt-and-kill fissure", "[mazes]") { + auto map = matrix::make(21, 21); + std::vector rooms; + std::vector dead_ends; + + maze::init(map); + maze::divide(map, {3,3}, {19,18}); + maze::hunt_and_kill(map, rooms, dead_ends, false); + + for(auto at : dead_ends) { + map[at.y][at.x]=32; + } + matrix::dump("FISSURE MAZE", map); + + REQUIRE(rooms.size() == 0); +} + + + +TEST_CASE("hunt-and-kill no-dead-ends", "[mazes]") { + auto map = matrix::make(21, 21); + std::vector rooms; + std::vector dead_ends; + + maze::init(map); + + maze::hunt_and_kill(map, rooms, dead_ends, false); + + maze::remove_dead_ends(map, dead_ends); + + matrix::dump("NO DEAD ENDS", map); +} + +TEST_CASE("hunt-and-kill too much", "[mazes]") { + auto map = matrix::make(21, 21); + std::vector rooms; + std::vector dead_ends; + + maze::init(map); + maze::inner_ring(map, 4, 2); + maze::divide(map, {3,3}, {19,18}); + auto copy = map; + + maze::hunt_and_kill(copy, rooms, dead_ends, false); + + + map = copy; + maze::randomize_rooms(rooms, dead_ends); + maze::hunt_and_kill(map, rooms, dead_ends, false); + + matrix::dump("NO DEAD ENDS", map); } diff --git a/worldbuilder.cpp b/worldbuilder.cpp index 367f13d..4de26bb 100644 --- a/worldbuilder.cpp +++ b/worldbuilder.cpp @@ -14,13 +14,8 @@ void WorldBuilder::generate_map() { // run it once to find dead ends maze::hunt_and_kill($map.$walls, $map.$rooms, $map.$dead_ends); - // use those dead ends to randomly place rooms - for(auto at : $map.$dead_ends) { - if(Random::uniform(0,1)) { - Room cur{at.x, at.y, 2, 2}; - $map.add_room(cur); - } - } + // randomize rooms based on dead ends + maze::randomize_rooms($map.$rooms, $map.$dead_ends); // run it again to create the final map with rooms // NOTE: hund_and_kill is responsible for clearing the map correctly