Add a terrible maze generation algorithm to test if a maze style map looks/feels better. The walls are disabled so you can walk around.
This commit is contained in:
parent
6cbfcf993e
commit
7a0b2f988d
9 changed files with 207 additions and 52 deletions
4
Makefile
4
Makefile
|
@ -26,7 +26,7 @@ tracy_build:
|
|||
meson compile -j 10 -C builddir
|
||||
|
||||
test: build
|
||||
./builddir/runtests
|
||||
./builddir/runtests "[maze-gen]"
|
||||
|
||||
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 "[maze-gen]"
|
||||
|
||||
win_installer:
|
||||
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp'
|
||||
|
|
|
@ -15,11 +15,11 @@ namespace gui {
|
|||
$gui.position(STATUS_UI_X, STATUS_UI_Y, STATUS_UI_WIDTH, STATUS_UI_HEIGHT);
|
||||
$gui.layout(
|
||||
"[ ritual_ui ]"
|
||||
"[inv_slot1 | inv_slot2 | inv_slot3]"
|
||||
"[inv_slot4 | inv_slot5 | inv_slot6]"
|
||||
"[*%(200,300)character_view|_|stat1]"
|
||||
"[_|_|stat2]"
|
||||
"[_|_|stat3]");
|
||||
"[inv_1|inv_2|inv_3]"
|
||||
"[inv_4|*%(200,300)character_view|_|inv_5]"
|
||||
"[inv_6|_|_ |inv_7]"
|
||||
"[inv_8|_|_ |inv_9]"
|
||||
"[inv_10|inv_11|inv_12]");
|
||||
|
||||
size_t inv_id = 0;
|
||||
for(auto [name, entity] : $gui.$name_ents) {
|
||||
|
@ -37,14 +37,9 @@ namespace gui {
|
|||
auto char_view = $gui.entity(name);
|
||||
$gui.set<Rectangle>(char_view, {});
|
||||
$gui.set<Sprite>(char_view, {"peasant_girl"});
|
||||
} else if(name.starts_with("stat")) {
|
||||
auto stat = $gui.entity(name);
|
||||
$gui.set<Rectangle>(stat, {});
|
||||
$gui.set<Label>(stat, {guecs::to_wstring(name)});
|
||||
} else {
|
||||
auto button = $gui.entity(name);
|
||||
$gui.set<Rectangle>(button, {});
|
||||
$gui.set<Textual>(button, {L""});
|
||||
$gui.set<ActionData>(button, {make_any<string>(name)});
|
||||
|
||||
if(name == "ritual_ui") {
|
||||
|
@ -53,6 +48,7 @@ namespace gui {
|
|||
});
|
||||
$gui.set<Sound>(button, {"pickup"});
|
||||
} else {
|
||||
$gui.set<Textual>(button, {guecs::to_wstring(name)});
|
||||
$gui.set<Clickable>(button, {
|
||||
[this](auto ent, auto data){ select_slot(ent, data); }
|
||||
});
|
||||
|
|
|
@ -17,8 +17,8 @@ LevelManager::LevelManager() {
|
|||
|
||||
LevelScaling LevelManager::scale_level() {
|
||||
return {
|
||||
20 + (5 * int($current_level)),
|
||||
15 + (5 * int($current_level))
|
||||
21,
|
||||
21
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace matrix {
|
|||
print("{:x}<", cell);
|
||||
} else if(cell == WALL_PATH_LIMIT) {
|
||||
print("# ");
|
||||
} else if(cell == 0) {
|
||||
print(". ");
|
||||
} else if(cell > 15 && cell < 32) {
|
||||
print("{:x}+", cell - 16);
|
||||
} else if(cell > 31) {
|
||||
|
|
145
maze.cpp
Normal file
145
maze.cpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
#include <fmt/core.h>
|
||||
#include <string>
|
||||
#include "rand.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "maze.hpp"
|
||||
|
||||
using std::string;
|
||||
using matrix::Matrix;
|
||||
|
||||
inline size_t rand(size_t i, size_t j) {
|
||||
if(i < j) {
|
||||
return Random::uniform(i, j);
|
||||
} else if(j < i) {
|
||||
return Random::uniform(j, i);
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool split_dir(size_t iDim, size_t jDim) {
|
||||
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));
|
||||
}
|
7
maze.hpp
Normal file
7
maze.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
#include "matrix.hpp"
|
||||
#include "map.hpp"
|
||||
|
||||
namespace maze {
|
||||
void recursive_div(matrix::Matrix& map, std::vector<Room>& rooms);
|
||||
}
|
|
@ -124,6 +124,7 @@ sources = [
|
|||
'textures.cpp',
|
||||
'tilemap.cpp',
|
||||
'worldbuilder.cpp',
|
||||
'maze.cpp'
|
||||
]
|
||||
|
||||
executable('runtests', sources + [
|
||||
|
@ -150,6 +151,7 @@ executable('runtests', sources + [
|
|||
'tests/stats.cpp',
|
||||
'tests/textures.cpp',
|
||||
'tests/tilemap.cpp',
|
||||
'tests/mazes.cpp',
|
||||
],
|
||||
cpp_args: cpp_args,
|
||||
link_args: link_args,
|
||||
|
|
23
tests/mazes.cpp
Normal file
23
tests/mazes.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <fmt/core.h>
|
||||
#include <string>
|
||||
#include "matrix.hpp"
|
||||
#include "rand.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "maze.hpp"
|
||||
|
||||
using std::string;
|
||||
using matrix::Matrix;
|
||||
|
||||
TEST_CASE("simple maze first attempt", "[maze-gen]") {
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
#include "components.hpp"
|
||||
#include "inventory.hpp"
|
||||
#include "rituals.hpp"
|
||||
#include "maze.hpp"
|
||||
|
||||
using namespace fmt;
|
||||
using namespace components;
|
||||
|
@ -103,20 +104,22 @@ 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;
|
||||
//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");
|
||||
}
|
||||
}
|
||||
}
|
||||
//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() {
|
||||
|
@ -134,33 +137,10 @@ void WorldBuilder::generate_rooms() {
|
|||
}
|
||||
|
||||
void WorldBuilder::generate_map() {
|
||||
generate_rooms();
|
||||
matrix::dump("BEFORE MAZE:", $map.$walls);
|
||||
maze::recursive_div($map.$walls, $map.$rooms);
|
||||
matrix::dump("AFTER MAZE:", $map.$walls);
|
||||
|
||||
PointList holes;
|
||||
for(size_t i = 0; i < $map.$rooms.size() - 1; i++) {
|
||||
tunnel_doors(holes, $map.$rooms[i], $map.$rooms[i+1]);
|
||||
}
|
||||
|
||||
// one last connection from first room to last
|
||||
tunnel_doors(holes, $map.$rooms.back(), $map.$rooms.front());
|
||||
|
||||
// place all the holes
|
||||
for(auto hole : holes) {
|
||||
|
||||
if(!matrix::inbounds($map.$walls, hole.x, hole.y)) {
|
||||
matrix::dump("MAP BEFORE CRASH", $map.$walls, hole.x, hole.y);
|
||||
|
||||
auto err = fmt::format("invalid hold target {},{} map is only {},{}",
|
||||
hole.x, hole.y, matrix::width($map.$walls),
|
||||
matrix::height($map.$walls));
|
||||
|
||||
dbc::sentinel(err);
|
||||
}
|
||||
|
||||
$map.$walls[hole.y][hole.x] = INV_SPACE;
|
||||
}
|
||||
|
||||
$map.invert_space();
|
||||
$map.expand();
|
||||
$map.load_tiles();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue