@ -18,6 +18,7 @@ void WorldBuilder::set_door(Room &room, int 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. " ) ;
int rand_x = Random : : uniform < int > ( 0 , room . width - 1 ) ;
int rand_x = Random : : uniform < int > ( 0 , room . width - 1 ) ;
int rand_y = Random : : uniform < int > ( 0 , room . height - 1 ) ;
int rand_y = Random : : uniform < int > ( 0 , room . height - 1 ) ;
@ -57,33 +58,51 @@ void WorldBuilder::partition_map(Room &cur, int depth) {
bool horiz = cur . width > cur . height ? false : true ;
bool horiz = cur . width > cur . height ? false : true ;
int split = make_split ( cur , horiz ) ;
int split = make_split ( cur , horiz ) ;
if ( split < = 0 ) return ; // end recursion
Room left = cur ;
Room left = cur ;
Room right = cur ;
Room right = cur ;
if ( horiz ) {
if ( horiz ) {
dbc : : check ( split > 0 , " split is not > 0 " ) ;
if ( split > = int ( cur . height ) ) return ; // end recursion
dbc : : check ( split < int ( cur . height ) , " split is too big! " ) ;
left . height = size_t ( split - 1 ) ;
left . height = size_t ( split - 1 ) ;
right . y = cur . y + split ;
right . y = cur . y + split ;
right . height = size_t ( cur . height - split ) ;
right . height = size_t ( cur . height - split ) ;
} else {
} else {
dbc : : check ( split > 0 , " split is not > 0 " ) ;
if ( split > = int ( cur . width ) ) return ; // end recursion
dbc : : check ( split < int ( cur . width ) , " split is too big! " ) ;
left . width = size_t ( split - 1 ) ;
left . width = size_t ( split - 1 ) ;
right . x = cur . x + split ,
right . x = cur . x + split ,
right . width = size_t ( cur . width - split ) ;
right . width = size_t ( cur . width - split ) ;
}
}
if ( depth > 0 & & left . width > 5 & & left . height > 5 ) {
if ( depth > 0 & & left . width > 2 & & left . height > 2 ) {
left . depth = depth - 1 ;
partition_map ( left , depth - 1 ) ;
partition_map ( left , depth - 1 ) ;
}
}
if ( depth > 0 & & right . width > 5 & & right . height > 5 ) {
if ( depth > 0 & & right . width > 2 & & right . height > 2 ) {
right . depth = depth - 1 ;
partition_map ( right , depth - 1 ) ;
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 : : tunnel_doors ( PointList & holes , Room & src , Room & target ) {
$ map . set_target ( target . entry ) ;
$ map . make_paths ( ) ;
bool found = dig_tunnel ( holes , src . exit , target . entry ) ;
dbc : : check ( found , " room should always be found " ) ;
$ map . INVARIANT ( ) ;
$ map . clear_target ( target . entry ) ;
}
void WorldBuilder : : generate ( ) {
void WorldBuilder : : generate ( ) {
Room root {
Room root {
. x = 0 ,
. x = 0 ,
@ -93,28 +112,28 @@ void WorldBuilder::generate() {
} ;
} ;
partition_map ( root , 10 ) ;
partition_map ( root , 10 ) ;
place_rooms ( root ) ;
$ map . INVARIANT ( ) ;
place_rooms ( ) ;
PointList holes ;
for ( size_t i = 0 ; i < $ map . $ rooms . size ( ) - 1 ; i + + ) {
for ( size_t i = 0 ; i < $ map . $ rooms . size ( ) - 1 ; i + + ) {
Room & src = $ map . $ rooms [ i ] ;
tunnel_doors ( holes , $ map . $ rooms [ i ] , $ map . $ rooms [ i + 1 ] ) ;
Room & target = $ map . $ rooms [ i + 1 ] ;
$ map . set_target ( target . entry ) ;
bool found = dig_tunnel ( src . exit , target . entry ) ;
if ( ! found ) {
println ( " ROOM NOT FOUND! " ) ;
}
$ map . clear_target ( target . entry ) ;
}
}
Room & src = $ map . $ rooms . back ( ) ;
// one last connection from first room to last
Room & target = $ map . $ rooms . front ( ) ;
tunnel_doors ( holes , $ map . $ rooms . back ( ) , $ map . $ rooms . front ( ) ) ;
$ map . set_target ( target . entry ) ;
// place all the holes
dig_tunnel ( src . exit , target . entry ) ;
for ( auto hole : holes ) {
$ map . clear_target ( target . entry ) ;
$ map . $ walls [ hole . y ] [ hole . x ] = INV_SPACE ;
}
// invert the whole map to finish it
for ( size_t y = 0 ; y < $ map . $ height ; + + y ) {
for ( size_t y = 0 ; y < $ map . $ height ; + + y ) {
for ( size_t x = 0 ; x < $ map . $ width ; + + x ) {
for ( size_t x = 0 ; x < $ map . $ width ; + + x ) {
// invert the map
$ map . $ walls [ y ] [ x ] = ! $ map . $ walls [ y ] [ x ] ;
$ map . $ walls [ y ] [ x ] = ! $ map . $ walls [ y ] [ x ] ;
}
}
}
}
@ -133,45 +152,39 @@ void WorldBuilder::make_room(size_t origin_x, size_t origin_y, size_t w, size_t
}
}
void WorldBuilder : : place_rooms ( Room & cur ) {
void WorldBuilder : : place_rooms ( ) {
for ( auto & cur : $ map . $ rooms ) {
for ( auto & cur : $ map . $ rooms ) {
cur . x + = 2 ;
cur . x + = 2 ;
cur . y + = 2 ;
cur . y + = 2 ;
cur . width - = 4 ;
cur . width - = 4 ;
cur . height - = 4 ;
cur . height - = 4 ;
add_door ( cur ) ;
add_door ( cur ) ;
set_door ( cur , INV_SPACE ) ;
make_room ( cur . x , cur . y , cur . width , cur . height ) ;
make_room ( cur . x , cur . y , cur . width , cur . height ) ;
}
}
}
}
bool WorldBuilder : : dig_tunnel ( Point & src , Point & target ) {
bool WorldBuilder : : dig_tunnel ( PointList & holes , Point & src , Point & target ) {
Matrix & paths = $ map . paths ( ) ;
Matrix & paths = $ map . paths ( ) ;
Matrix & walls = $ map . walls ( ) ;
int limit = $ map . limit ( ) ;
walls [ src . y ] [ src . x ] = INV_WALL ;
walls [ target . y ] [ target . x ] = INV_WALL ;
// for the walk this needs to be walls since it's inverted?
dbc : : check ( paths [ src . y ] [ src . x ] ! = limit ,
dbc : : check ( walls [ src . y ] [ src . x ] = = INV_WALL ,
" source room has path as a wall " ) ;
" src room has a wall at exit door " ) ;
dbc : : check ( paths [ target . y ] [ target . x ] ! = limit ,
dbc : : check ( walls [ target . y ] [ target . x ] = = INV_WALL ,
" target room has path as a wall " ) ;
" target room has a wall at entry door " ) ;
$ map . make_paths ( ) ;
bool found = false ;
bool found = false ;
Point out { src . x , src . y } ;
Point out { src . x , src . y } ;
int count = 0 ;
int count = 0 ;
do {
do {
walls [ out . y ] [ out . x ] = INV_SPACE ;
found = $ map . neighbors ( out , true ) ;
found = $ map . neighbors ( out , true ) ;
holes . push_back ( out ) ;
if ( paths [ out . y ] [ out . x ] = = 0 ) {
if ( paths [ out . y ] [ out . x ] = = 0 ) {
walls [ out . y ] [ out . x ] = INV_SPACE ;
return true ;
return true ;
}
}
} while ( found & & out . x > 0 & & out . y > 0 & & + + count < 1 00) ;
} while ( found & & + + count < 2 00) ;
return false ;
return false ;
}
}