@ -1,5 +1,6 @@
# include "map.hpp"
# include "dbc.hpp"
# include "rand.hpp"
# include <vector>
# include <array>
# include <fmt/core.h>
@ -8,11 +9,21 @@
using std : : vector , std : : pair ;
using namespace fmt ;
void dump_map ( const std : : string & msg , Matrix & map ) {
void dump_map ( const std : : string & msg , Matrix & map , int show_x , int show_y ) {
println ( " ----------------- {} " , msg ) ;
for ( auto row : map ) {
for ( auto col : row ) {
print ( " {} " , col ) ;
for ( size_t y = 0 ; y < map . size ( ) ; y + + ) {
for ( size_t x = 0 ; x < map [ y ] . size ( ) ; x + + ) {
int col = map [ y ] [ x ] ;
if ( int ( x ) = = show_x & & int ( y ) = = show_y ) {
print ( " {:x}< " , col ) ;
} else if ( col = = 1000 ) {
print ( " # " ) ;
} else if ( col > 15 ) {
print ( " * " ) ;
} else {
print ( " {:x} " , col ) ;
}
}
print ( " \n " ) ;
}
@ -62,8 +73,9 @@ bool Map::iswall(size_t x, size_t y) {
return $ walls [ y ] [ x ] = = WALL_VALUE ;
}
void Map : : dump ( ) {
dump_map ( " WALLS " , $ walls ) ;
void Map : : dump ( int show_x , int show_y ) {
dump_map ( " WALLS " , walls ( ) , show_x , show_y ) ;
dump_map ( " PATHS " , paths ( ) , show_x , show_y ) ;
}
bool Map : : can_move ( Point move_to ) {
@ -81,51 +93,84 @@ Point Map::center_camera(const Point &around, size_t view_x, size_t view_y) {
int center_x = int ( around . x - view_x / 2 ) ;
int center_y = int ( around . y - view_y / 2 ) ;
// BUG: is clamp really the best thing here? this seems wrong.
size_t start_x = high_x > 0 ? std : : clamp ( center_x , 0 , high_x ) : 0 ;
size_t start_y = high_y > 0 ? std : : clamp ( center_y , 0 , high_y ) : 0 ;
return { start_x , start_y } ;
}
bool Map : : neighbors ( Point & out , bool greater ) {
/*
* Finds the next optimal neighbor in the path
* using either a direct or random method .
*
* Both modes will pick a random direction to start
* looking for the next path , then it goes clock - wise
* from there .
*
* In the direct method it will attempt to find
* a path that goes 1 lower in the dijkstra map
* path , and if it can ' t find that it will go to
* a 0 path ( same number ) .
*
* In random mode it will pick either the next lower
* or the same level depending on what it finds first .
* Since the starting direction is random this will
* give it a semi - random walk that eventually gets to
* the target .
*
* In map generation this makes random paths and carves
* up the space to make rooms more irregular .
*
* When applied to an enemy they will either go straight
* to the player ( random = false ) or they ' ll wander around
* drunkenly gradually reaching the player , and dodging
* in and out .
*/
bool Map : : neighbors ( Point & out , bool random ) {
Matrix & paths = $ paths . $ paths ;
bool zero_found = false ;
// just make a list of the four directions
std : : array < Point , 4 > dirs { {
{ out . x , out . y - 1 } ,
{ out . x + 1 , out . y } ,
{ out . x , out . y + 1 } ,
{ out . x - 1 , out . y }
{ out . x , out . y - 1 } , // north
{ out . x + 1 , out . y } , // east
{ out . x , out . y + 1 } , // south
{ out . x - 1 , out . y } // west
} } ;
int zero_i = - 1 ;
// get the current dijkstra number
int cur = paths [ out . y ] [ out . x ] ;
// BUG: sometimes cur is in a wall so finding neighbors fails
for ( size_t i = 0 ; i < dirs . size ( ) ; + + i ) {
Point dir = dirs [ i ] ;
int target = inmap ( dir . x , dir . y ) ? paths [ dir . y ] [ dir . x ] : $ limit ;
if ( target = = $ limit ) continue ; // skip unpathable stuff
// pick a random start of directions
int rand_start = Random : : uniform < int > ( 0 , dirs . size ( ) ) ;
int diff = cur - target ;
// go through all possible directions
for ( size_t i = 0 ; i < dirs . size ( ) ; i + + ) {
// but start at the random start, effectively randomizing
// which valid direction to go
Point dir = dirs [ ( i + rand_start ) % dirs . size ( ) ] ;
if ( ! inmap ( dir . x , dir . y ) ) continue ; //skip unpathable stuff
int weight = cur - paths [ dir . y ] [ dir . x ] ;
if ( diff = = 1 ) {
out = { . x = dir . x , . y = dir . y } ;
if ( weight = = 1 ) {
// no matter what we follow direct paths
out = dir ;
return true ;
} else if ( diff = = 0 ) {
zero_i = i ;
}
}
if ( zero_i ! = - 1 ) {
out = { . x = dirs [ zero_i ] . x , . y = dirs [ zero_i ] . y } ;
} else if ( random & & weight = = 0 ) {
// if random is selected and it's a 0 path take it
out = dir ;
return true ;
} else {
return false ;
} else if ( weight = = 0 ) {
// otherwise keep the last zero path for after
out = dir ;
zero_found = true ;
}
}
// if we reach this then either zero was found and
// zero_found is set true, or it wasn't and nothing found
return zero_found ;
}
bool Map : : INVARIANT ( ) {
using dbc : : check ;
@ -133,5 +178,14 @@ bool Map::INVARIANT() {
check ( $ walls . size ( ) = = height ( ) , " walls wrong height " ) ;
check ( $ walls [ 0 ] . size ( ) = = width ( ) , " walls wrong width " ) ;
for ( auto room : $ rooms ) {
check ( int ( room . x ) > = 0 & & int ( room . y ) > = 0 ,
format ( " room depth={} has invalid position {},{} " ,
room . depth , room . x , room . y ) ) ;
check ( int ( room . width ) > 0 & & int ( room . height ) > 0 ,
format ( " room depth={} has invalid dims {},{} " ,
room . depth , room . width , room . height ) ) ;
}
return true ;
}