Mostly cleaned up world get to handle more rooms and paths, but rando_rect needs to be actually random.

This commit is contained in:
Zed A. Shaw 2025-01-12 14:57:54 -05:00
parent c19c53b15b
commit e9277bf052
11 changed files with 257 additions and 39 deletions

View file

@ -53,9 +53,10 @@ void WorldBuilder::add_door(Room &room) {
}
void WorldBuilder::partition_map(Room &cur, int depth) {
if(cur.width >= 5 && cur.width <= 10 &&
cur.height >= 5 && cur.height <= 10) {
$map.$rooms.push_back(cur);
if(cur.width >= 3 && cur.width <= 6 &&
cur.height >= 3 && cur.height <= 6)
{
$map.add_room(cur);
return;
}
@ -97,9 +98,11 @@ void WorldBuilder::update_door(Point &at, int wall_or_space) {
void WorldBuilder::stylize_room(int room, string tile_name, float size) {
Point center = $map.place_entity(room);
Point pos_out;
bool placed = $map.place_entity(room, pos_out);
dbc::check(placed, "failed to place style in room");
for(matrix::circle it{$map.$walls, center, size}; it.next();) {
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)) {
$map.$tiles.set_tile(x, it.y, tile_name);
@ -108,22 +111,24 @@ void WorldBuilder::stylize_room(int room, string tile_name, float size) {
}
}
void WorldBuilder::generate_map() {
PointList holes;
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() {
generate_rooms();
PointList holes;
for(size_t i = 0; i < $map.$rooms.size() - 1; i++) {
tunnel_doors(holes, $map.$rooms[i], $map.$rooms[i+1]);
}
@ -133,14 +138,21 @@ void WorldBuilder::generate_map() {
// 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;
}
for(matrix::each_cell it{$map.$walls}; it.next();) {
int is_wall = !$map.$walls[it.y][it.x];
$map.$walls[it.y][it.x] = is_wall;
}
$map.invert_space();
$map.expand();
$map.load_tiles();
@ -159,9 +171,11 @@ void WorldBuilder::generate_map() {
DinkyECS::Entity place_item(DinkyECS::World &world, Map &game_map, std::string name, int in_room) {
auto &config = world.get_the<GameConfig>();
auto item = world.entity();
auto pos = game_map.place_entity(in_room);
Point pos_out;
bool placed = game_map.place_entity(in_room, pos_out);
dbc::check(placed, "failed to randomly place item in room");
json item_data = config.items[name];
world.set<Position>(item, {pos.x+1, pos.y+1});
world.set<Position>(item, {pos_out.x+1, pos_out.y+1});
if(item_data["inventory_count"] > 0) {
world.set<InventoryItem>(item, {item_data["inventory_count"], item_data});
@ -178,7 +192,9 @@ DinkyECS::Entity place_combatant(DinkyECS::World &world, Map &game_map, std::str
auto &config = world.get_the<GameConfig>();
auto enemy = world.entity();
auto enemy_data = config.enemies[name];
auto pos = game_map.place_entity(in_room);
Point pos;
bool placed = game_map.place_entity(in_room, pos);
dbc::check(placed, "failed to place combatant in room");
world.set<Position>(enemy, {pos});
if(enemy_data.contains("components")) {
@ -250,11 +266,8 @@ void WorldBuilder::make_room(size_t origin_x, size_t origin_y, size_t w, size_t
void WorldBuilder::place_rooms() {
for(auto &cur : $map.$rooms) {
cur.x += WORLDBUILD_SHRINK;
cur.y += WORLDBUILD_SHRINK;
cur.width -= WORLDBUILD_SHRINK * 2;
cur.height -= WORLDBUILD_SHRINK * 2;
// println("ROOM x/y={},{}; w/h={},{}; map={},{}",
// cur.x, cur.y, cur.width, cur.height, $map.$width, $map.$height);
add_door(cur);
make_room(cur.x, cur.y, cur.width, cur.height);
}
@ -281,24 +294,34 @@ inline bool random_path(Map &map, PointList &holes, Point src, Point target) {
return target_found;
}
inline void straight_path(PointList &holes, Point src, Point target) {
inline void straight_path(Map &map, PointList &holes, Point src, Point target) {
for(matrix::line dig{src, target}; dig.next();) {
holes.push_back({size_t(dig.x), size_t(dig.y)});
holes.push_back({size_t(dig.x+1), 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, 3);
switch(path_type) {
case 0:
// for now do 25% as simple straight paths
straight_path(holes, src.exit, target.entry);
straight_path($map, holes, src.exit, target.entry);
break;
case 1:
// for now do 25% as simple straight paths
straight_path($map, holes, src.exit, target.entry);
break;
default:
// then do the rest as random with fallback
if(!random_path($map, holes, src.exit, target.entry)) {
straight_path(holes, src.exit, target.entry);
straight_path($map, holes, src.exit, target.entry);
}
}
}