2022-04-24 19:48:45 +02:00
namespace nilrider {
2022-05-05 22:37:05 +02:00
const int steps_per_block = 16 ;
const int texture_density = 64 ;
void level : : init_textures ( ) {
2022-05-06 19:51:46 +02:00
create_castle ( ) ;
2022-05-05 22:37:05 +02:00
int tY = isize ( map_tiles ) ;
int tX = isize ( map_tiles [ 0 ] ) ;
2024-08-19 12:33:39 +02:00
int ttY = next_p2 ( tY ) ;
int ttX = next_p2 ( tX ) ;
2022-05-05 22:37:05 +02:00
2022-05-09 10:02:21 +02:00
transmatrix T = gpushxto0 ( new_levellines_for ) ;
2022-05-05 22:37:05 +02:00
2022-05-09 10:02:21 +02:00
for ( int which : { 0 , 1 , 2 } ) {
2022-05-05 22:37:05 +02:00
2022-05-09 10:02:21 +02:00
bool stepped = which = = 1 ;
bool levels = which = = 2 ;
auto & target = stepped ? unil_texture_stepped : levels ? unil_texture_levels : unil_texture ;
if ( target & & ! ( levels & & levellines_for ! = new_levellines_for ) ) continue ;
bool regen = ! target ;
if ( regen ) target = new texture : : texture_data ;
2022-05-05 22:37:05 +02:00
auto & tex = * target ;
2022-05-09 10:02:21 +02:00
if ( regen ) {
2024-08-19 12:33:39 +02:00
tex . twidth = tex . tx = ttX * texture_density ;
tex . theight = tex . ty = ttY * texture_density ;
2022-05-09 10:02:21 +02:00
tex . stretched = false ;
tex . strx = tex . tx ;
tex . stry = tex . ty ;
tex . base_x = 0 ;
tex . base_y = 0 ;
tex . whitetexture ( ) ;
}
2022-05-05 22:37:05 +02:00
auto getpix = [ & ] ( int x , int y ) {
int px = x / pixel_per_block ;
int py = y / pixel_per_block ;
if ( px < 0 | | py < 0 | | px > = tX | | py > = tY ) return ' ! ' ;
char bmch = map_tiles [ py ] [ px ] ;
if ( bmch = = ' ! ' ) return ' ! ' ;
return submaps [ bmch ] [ y % pixel_per_block ] [ x % pixel_per_block ] ;
} ;
int subpixels = texture_density / pixel_per_block ;
int stepdiv = texture_density / steps_per_block ;
for ( int y = 0 ; y < tex . ty ; y + + )
for ( int x = 0 ; x < tex . tx ; x + + ) {
color_t col ;
if ( ! stepped ) {
char c = getpix ( x / subpixels , y / subpixels ) ;
col = bcols [ c ] ;
2022-05-09 10:02:21 +02:00
if ( levels & & new_levellines_for [ 3 ] ) {
hyperpoint h = T * mappt ( x , y , texture_density ) ;
2024-08-18 21:43:28 +02:00
ld z = h [ 2 ] - nilv : : convert_bonus ( h , nilv : : nmSym , nilv : : model_used ) ;
2022-05-09 10:02:21 +02:00
if ( z > 0 ) col = gradient ( col , 0xFFFF0000 , 0 , z - floor ( z ) , 4 ) ;
if ( z < 0 ) col = gradient ( col , 0xFF0000FF , 0 , - z - floor ( - z ) , 4 ) ;
}
2022-05-05 22:37:05 +02:00
}
else {
int mx = x % stepdiv ;
int my = y % stepdiv ;
int mx0 , mx1 , my0 , my1 ;
if ( mx < stepdiv / 2 ) { mx0 = mx1 = 2 * mx ; } else { mx0 = stepdiv - 2 ; mx1 = stepdiv ; }
if ( my < stepdiv / 2 ) { my0 = my1 = 2 * my ; } else { my0 = stepdiv - 2 ; my1 = stepdiv ; }
int ax = ( x / stepdiv ) * stepdiv ;
int ay = ( y / stepdiv ) * stepdiv ;
2022-05-06 12:00:22 +02:00
ld maxh = - HUGE_VAL ;
char c = ' ! ' ;
for ( int i = 0 ; i < 4 ; i + + ) {
hyperpoint h = mappt ( ax + ( ( mx0 ! = mx1 ) ? ( i & 1 ? 3 : 1 ) * stepdiv / 2 : mx0 ) , ay + ( ( my0 ! = my1 ) ? ( i & 2 ? 3 : 1 ) * stepdiv / 2 : my0 ) , texture_density ) ;
if ( h [ 2 ] > maxh ) {
c = getpix ( ( ( i & 1 ? mx1 : mx0 ) + ax ) / subpixels , ( ( i & 2 ? my1 : my0 ) + ay ) / subpixels ) ;
if ( c ! = ' ! ' ) maxh = h [ 2 ] ;
}
}
col = bcols [ c ] ;
2022-05-05 22:37:05 +02:00
if ( mx0 ! = mx1 ) col = gradient ( col , 0xFF000000 , 0 , .1 , 1 ) ;
if ( my0 ! = my1 ) col = gradient ( col , 0xFF000000 , 0 , .2 , 1 ) ;
}
tex . get_texture_pixel ( x , y ) = col ;
tex . get_texture_pixel ( x , y ) | = 0xFF000000 ;
2022-05-09 10:02:21 +02:00
if ( ! levels )
tex . get_texture_pixel ( x , y ) ^ = hrand ( 0x1000000 ) & 0xF0F0F ;
2022-05-05 22:37:05 +02:00
}
tex . loadTextureGL ( ) ;
}
2022-05-09 10:02:21 +02:00
levellines_for = new_levellines_for ;
2022-05-05 22:37:05 +02:00
}
2022-05-06 17:10:10 +02:00
void level : : init_shapes ( ) {
2022-05-06 13:14:48 +02:00
check_cgi ( ) ;
2022-05-06 17:10:10 +02:00
string s = " nillevel- " + name ;
if ( cgi . ext . count ( s ) ) return ;
cgi . ext [ s ] = nullptr ;
2022-04-24 19:48:45 +02:00
int tY = isize ( map_tiles ) ;
int tX = isize ( map_tiles [ 0 ] ) ;
2024-08-19 12:33:39 +02:00
int ttY = next_p2 ( tY ) ;
int ttX = next_p2 ( tX ) ;
2022-04-24 19:48:45 +02:00
2022-05-06 17:10:10 +02:00
for ( int s = 0 ; s < 3 ; s + + ) {
if ( euclid & & s ! = 1 ) continue ;
if ( nil & & s = = 1 ) continue ;
2022-05-05 22:37:05 +02:00
cgi . bshape ( s = = 0 ? shFloor : s = = 1 ? shPlanFloor : shStepFloor , PPR : : WALL ) ;
2022-04-24 19:48:45 +02:00
shFloor . flags | = POLY_TRIANGLES ;
shPlanFloor . flags | = POLY_TRIANGLES ;
2022-05-05 22:37:05 +02:00
shStepFloor . flags | = POLY_TRIANGLES ;
int prec = 16 ;
2022-05-06 12:00:22 +02:00
if ( s = = 2 ) prec * = 4 ;
2022-05-05 22:37:05 +02:00
int cdiv = prec / steps_per_block ;
2022-05-06 21:08:15 +02:00
prec > > = reduce_quality ;
2022-04-24 19:48:45 +02:00
2022-05-06 17:10:10 +02:00
bool need_uniltinf = uniltinf . tvertices . empty ( ) ;
2022-05-06 12:00:22 +02:00
auto pt = [ & ] ( int x , int y , int qx , int qy ) {
2024-08-19 12:33:39 +02:00
if ( need_uniltinf ) uniltinf . tvertices . push_back ( glhr : : makevertex ( x * 1. / ttX / prec , y * 1. / ttY / prec , 0 ) ) ;
2022-05-06 12:00:22 +02:00
if ( s = = 2 ) {
ld ax = x , ay = y ;
if ( qx ) {
if ( x % cdiv = = cdiv / 2 + 1 ) qx = 0 ;
}
else {
ax - = ( x % cdiv ) ;
ax + = .5 ;
ax + = ( x % cdiv ) * ( cdiv / 2 - 1. ) / ( cdiv / 2 ) ;
}
if ( qy ) {
if ( y % cdiv = = cdiv / 2 + 1 ) qy = 0 ;
}
else {
ay - = ( y % cdiv ) ;
ay + = .5 ;
ay + = ( y % cdiv ) * ( cdiv / 2 - 1. ) / ( cdiv / 2 ) ;
}
2024-08-19 12:33:39 +02:00
uniltinf_stepped . tvertices . push_back ( glhr : : makevertex ( ( ax + qx ) / ttX / prec , ( ay + qy ) / ttY / prec , 0 ) ) ;
2022-05-06 12:00:22 +02:00
}
2022-05-05 22:37:05 +02:00
hyperpoint h = mappt ( x , y , prec ) ;
if ( s = = 2 ) {
if ( x % cdiv = = cdiv / 2 + 1 ) x + = cdiv / 2 - 1 ;
if ( y % cdiv = = cdiv / 2 + 1 ) y + = cdiv / 2 - 1 ;
int gx = x / cdiv * cdiv + ( x % cdiv ) * 2 ;
int gy = y / cdiv * cdiv + ( y % cdiv ) * 2 ;
hyperpoint gh = mappt ( gx , gy , prec ) ;
int ax = x / cdiv * cdiv + cdiv / 2 ;
int ay = y / cdiv * cdiv + cdiv / 2 ;
hyperpoint ah = mappt ( ax , ay , prec ) ;
gh [ 0 ] = gh [ 0 ] - ah [ 0 ] ;
gh [ 1 ] = gh [ 1 ] - ah [ 1 ] ;
gh [ 2 ] = 0 ;
2023-01-30 01:20:12 +01:00
gh = sym_to_used ( gh ) ;
2022-05-05 22:37:05 +02:00
h = rgpushxto0 ( ah ) * gh ;
ld delta = 0 ;
// make sure steps are below the actual level
for ( int z = 0 ; z < 4 ; z + + ) {
int zx = x / cdiv * cdiv + ( ( z & 1 ) ? cdiv : 0 ) ;
int zy = y / cdiv * cdiv + ( ( z & 2 ) ? cdiv : 0 ) ;
hyperpoint zh = mappt ( zx , zy , prec ) ;
hyperpoint uh ;
uh [ 0 ] = zh [ 0 ] - ah [ 0 ] ;
uh [ 1 ] = zh [ 1 ] - ah [ 1 ] ;
uh [ 2 ] = 0 ; uh [ 3 ] = 1 ;
2023-01-30 01:20:12 +01:00
uh = sym_to_used ( uh ) ;
2022-05-05 22:37:05 +02:00
uh = rgpushxto0 ( ah ) * uh ;
delta = max ( delta , uh [ 2 ] - zh [ 2 ] ) ;
}
h [ 2 ] - = delta ;
}
2022-04-24 19:48:45 +02:00
real_minx = min ( real_minx , h [ 0 ] ) ;
real_maxx = max ( real_maxx , h [ 0 ] ) ;
real_miny = min ( real_miny , h [ 1 ] ) ;
real_maxy = max ( real_maxy , h [ 1 ] ) ;
if ( s = = 1 ) h [ 2 ] = h [ 3 ] = 1 ;
cgi . hpcpush ( h ) ;
} ;
2022-05-05 22:37:05 +02:00
for ( int y = 0 ; y < tY * prec ; y + + )
for ( int x = 0 ; x < tX * prec ; x + + ) {
char bmch = map_tiles [ y / prec ] [ x / prec ] ;
2022-04-24 19:48:45 +02:00
if ( bmch = = ' ! ' ) continue ;
2022-05-06 12:00:22 +02:00
int qx = 0 , qy = 0 ;
2022-05-05 22:37:05 +02:00
if ( s = = 2 ) {
2022-05-06 12:00:22 +02:00
if ( x % cdiv = = ( cdiv / 2 ) ) qx + + ;
if ( x % cdiv > ( cdiv / 2 ) ) qx + = 2 ;
if ( y % cdiv = = ( cdiv / 2 ) ) qy + + ;
if ( y % cdiv > ( cdiv / 2 ) ) qy + = 2 ;
if ( qx + qy > 1 ) continue ;
2022-05-05 22:37:05 +02:00
}
2022-05-06 12:00:22 +02:00
pt ( x , y , qx , qy ) ;
pt ( x , y + 1 , qx , qy ) ;
pt ( x + 1 , y , qx , qy ) ;
pt ( x + 1 , y + 1 , qx , qy ) ;
pt ( x + 1 , y , qx , qy ) ;
pt ( x , y + 1 , qx , qy ) ;
2022-04-24 19:48:45 +02:00
}
cgi . finishshape ( ) ;
}
if ( 1 ) {
cgi . bshape ( shField , PPR : : WALL ) ;
shField . flags | = POLY_TRIANGLES ;
auto pt = [ & ] ( hyperpoint p ) {
hyperpoint h = mappt ( p [ 0 ] , p [ 1 ] , 16 ) ;
h [ 2 ] + = p [ 2 ] ;
cgi . hpcpush ( h ) ;
// cgi.hpcpush(hyperpoint(rand() % 10 - 5, rand() % 10 - 5, rand() % 10 - 5, 1));
} ;
for ( int y = 0 ; y < tY * 16 ; y + + )
for ( int x = 0 ; x < tX * 16 ; x + + ) {
int bx = x / 16 ;
int by = y / 16 ;
char bmch = map_tiles [ by ] [ bx ] ;
if ( bmch = = ' f ' & & ( x & 1 ) & & ( y & 1 ) ) {
for ( int s = 0 ; s < 4 ; s + + ) {
hyperpoint st = point3 ( x + .1 , y + .1 , 0 ) ;
2022-11-12 22:38:45 +01:00
hyperpoint a = spin ( 90. _deg * s ) * point3 ( .1 , .1 , 0 ) ;
hyperpoint b = spin ( 90. _deg * ( s + 1 ) ) * point3 ( .1 , .1 , 0 ) ;
2022-04-24 19:48:45 +02:00
hyperpoint hi = point3 ( 0 , 0 , 1 ) ;
for ( int z = 0 ; z < 3 ; z + + ) {
ld z1 = ( 3 - z ) / 3. ;
ld z2 = ( 2 - z ) / 3. ;
pt ( st + a * z1 + hi * z ) ;
pt ( st + b * z1 + hi * z ) ;
pt ( st + a * z2 + hi * ( z + 1 ) ) ;
pt ( st + a * z2 + hi * ( z + 1 ) ) ;
pt ( st + b * z1 + hi * z ) ;
pt ( st + b * z2 + hi * ( z + 1 ) ) ;
}
}
}
}
cgi . finishshape ( ) ;
}
if ( 1 ) {
cgi . bshape ( shCastle , PPR : : WALL ) ;
shCastle . flags | = POLY_TRIANGLES ;
for ( int y = 0 ; y < tY ; y + + )
for ( int x = 0 ; x < tX ; x + + ) {
char bmch = map_tiles [ y ] [ x ] ;
if ( bmch = = ' r ' ) {
for ( int s = 0 ; s < 4 ; s + + ) {
hyperpoint ctr = mappt ( x + .5 , y + .5 , 1 ) ;
ctr [ 2 ] + = safe_alt ( ctr ) + .5 * scale ;
ld need = safe_alt ( ctr , - 1 ) / scale / scale ;
int max_y = need * 2 + 1 ;
2022-11-12 22:38:45 +01:00
hyperpoint a = spin ( 90. _deg * s ) * point3 ( 1 , 0 , 0 ) ;
hyperpoint b = spin ( 90. _deg * s ) * point3 ( 0 , 1 , 0 ) ;
2022-04-24 19:48:45 +02:00
auto pt = [ & ] ( ld af , ld bf , ld yf ) {
hyperpoint ha = a * af * scale ; ha [ 3 ] = 1 ;
hyperpoint hb = b * bf * scale ; hb [ 3 ] = 1 ;
hyperpoint res = rgpushxto0 ( ctr ) * rgpushxto0 ( ha ) * rgpushxto0 ( hb ) * point31 ( 0 , 0 , yf * scale * scale ) ;
cgi . hpcpush ( res ) ;
} ;
auto ptf = [ & ] ( ld af , ld bf , ld yf ) {
pt ( af , bf , yf ) ;
castle_tinf . tvertices . push_back ( glhr : : makevertex ( bf , yf * 4 , 0 ) ) ;
} ;
auto ptc = [ & ] ( ld af , ld bf , ld yf , ld xt , ld yt ) {
pt ( af , bf , yf ) ;
castle_tinf . tvertices . push_back ( glhr : : makevertex ( xt , yt , 0 ) ) ;
} ;
for ( int w = 0 ; w < 2 ; w + + )
for ( int as = 0 ; as < 8 ; as + + )
for ( int y = 0 ; y < max_y ; y + + ) {
ld xf = w ? .4 : .5 ;
ld y1 = - y / 2. ;
ld y2 = - ( y + 1 ) / 2. ;
ld asd = ( as - 4 ) / 8. ;
ld asd1 = ( as - 3 ) / 8. ;
auto oasd = asd / 4 ;
if ( w ) asd * = .8 , asd1 * = .8 , oasd * = .8 * .8 ;
ptf ( xf , asd , y1 - oasd ) ;
ptf ( xf , asd1 , y1 - oasd ) ;
ptf ( xf , asd , y2 - oasd ) ;
ptf ( xf , asd , y2 - oasd ) ;
ptf ( xf , asd1 , y1 - oasd ) ;
ptf ( xf , asd1 , y2 - oasd ) ;
}
ld x1 = 1 / 32. ;
ld x2 = 1 / 4. + x1 ;
ld y1 = 1 / 32. ;
ld y2 = 1 / 8. + x1 ;
for ( int as = 0 ; as < 8 ; as + + ) {
ld asd = ( as - 4 ) / 8. ;
ld asd1 = ( as - 3 ) / 8. ;
ld asdw = asd * .8 ;
ld asdw1 = asd1 * .8 ;
ld asd2 = ( as - 5 ) / 8. ;
//ld asdw2 = asd2 * .8;
ld oasd = asd / 4 ;
ld oasdw = oasd * .8 * .8 ;
ld oasd2 = asd2 / 4 ;
ld oasdw2 = oasd2 * .8 * .8 ;
/* tops */
ptc ( .5 , asd , - oasd , x1 , y1 ) ;
ptc ( .5 , asd1 , - oasd , x1 , y2 ) ;
ptc ( .4 , asdw , - oasdw , x2 , y1 ) ;
ptc ( .4 , asdw , - oasdw , x2 , y1 ) ;
ptc ( .5 , asd1 , - oasd , x1 , y2 ) ;
ptc ( .4 , asdw1 , - oasdw , x2 , y2 ) ;
/* sides */
ptc ( .5 , asd , - oasd , x1 , y1 ) ;
ptc ( .5 , asd , - oasd2 , x1 , y2 ) ;
ptc ( .4 , asdw , - oasdw , x2 , y1 ) ;
ptc ( .4 , asdw , - oasdw , x2 , y1 ) ;
ptc ( .5 , asd , - oasd2 , x1 , y2 ) ;
ptc ( .4 , asdw , - oasdw2 , x2 , y2 ) ;
}
}
2022-05-06 17:10:10 +02:00
}
}
cgi . finishshape ( ) ;
}
cgi . extra_vertices ( ) ;
}
void level : : init ( ) {
if ( initialized ) return ;
2024-08-18 21:22:20 +02:00
if ( this = = & multifloor ) {
for ( int y = 1 ; y < = 4 ; y + + ) {
auto l = new level ( * this ) ;
l - > name = l - > name + " # " + its ( y ) ;
2024-08-18 21:43:28 +02:00
l - > surface = [ y ] ( hyperpoint h ) { return rot_plane ( h ) - 3 * y ; } ;
2024-08-18 21:22:20 +02:00
l - > map_tiles [ 1 ] [ 1 ] = ' * ' ;
l - > sublevels = { } ;
sublevels . push_back ( l ) ;
}
}
2022-05-06 17:10:10 +02:00
initialized = true ;
2024-08-18 21:22:20 +02:00
2022-05-06 17:10:10 +02:00
check_cgi ( ) ;
real_minx = HUGE_VAL ;
real_miny = HUGE_VAL ;
real_maxx = - HUGE_VAL ;
real_maxy = - HUGE_VAL ;
if ( flags & nrlPolar )
scale = 1 ;
else
scale = abs ( maxx - minx ) / isize ( map_tiles [ 0 ] ) ;
println ( hlog , " SCALE IS " , this - > scale ) ;
2022-05-09 12:42:40 +02:00
levellines_for = new_levellines_for = Hypc ;
2022-05-09 10:02:21 +02:00
2022-05-06 17:10:10 +02:00
if ( 1 ) {
int tY = isize ( map_tiles ) ;
int tX = isize ( map_tiles [ 0 ] ) ;
for ( int y = 0 ; y < tY ; y + + )
for ( int x = 0 ; x < tX ; x + + ) {
char bmch = map_tiles [ y ] [ x ] ;
2022-04-24 19:48:45 +02:00
if ( bmch = = ' o ' ) {
hyperpoint h = mappt ( x + .5 , y + .5 , 1 ) ;
h [ 2 ] + = safe_alt ( h ) + 1 ;
statues . emplace_back ( statue { rgpushxto0 ( h ) , & shBall , 0xFFFFFFFF } ) ;
}
if ( bmch = = ' x ' ) {
hyperpoint h = mappt ( x + .5 , y + .5 , 1 ) ;
statues . emplace_back ( statue { rgpushxto0 ( h ) , & shGeostatue , 0xFFFFFFFF } ) ;
}
2022-04-30 12:01:18 +02:00
if ( bmch = = ' * ' ) {
hyperpoint h = mappt ( x + .5 , y + .5 , 1 ) ;
h [ 2 ] + = safe_alt ( h , .5 , .85 ) ;
triangledata d ;
d . where = h ;
d . x = x ;
d . y = y ;
2024-08-18 21:21:18 +02:00
d . which = this ;
2022-04-30 12:01:18 +02:00
for ( int i = 0 ; i < 7 ; i + + )
d . colors [ i ] = gradient ( 0xFFD500FF , 0xFF , 0 , i , 8 ) ;
2022-05-05 22:36:30 +02:00
d . colors [ 6 ] = d . colors [ 0 ] ;
2022-04-30 12:01:18 +02:00
triangles . emplace_back ( d ) ;
}
2024-08-18 01:28:34 +02:00
if ( flags & nrlSwapTriangleOrder )
sort ( triangles . begin ( ) , triangles . end ( ) , [ ] ( triangledata & d1 , triangledata & d2 ) { return tie ( d1 . x , d1 . y ) < tie ( d2 . x , d2 . y ) ; } ) ;
2022-04-24 19:48:45 +02:00
}
cgi . finishshape ( ) ;
}
2022-05-06 17:10:10 +02:00
start . where = mappt ( startx + .5 , starty + .5 , 1 ) ;
start . t = 0 ;
start . timer = 0 ;
2024-08-18 13:06:04 +02:00
start . on_surface = this ;
start . sstime = - 100 ;
2024-08-18 15:43:19 +02:00
start . last_tramp = - 100 ;
2024-08-20 10:17:50 +02:00
start . collected_triangles = 0 ;
2024-08-20 10:35:14 +02:00
start . goals = 0 ;
start . failed = 0 ;
2024-08-20 10:17:50 +02:00
start . vel = 0 ;
2022-05-06 17:10:10 +02:00
current = start ;
println ( hlog , " start.where = " , start . where ) ;
2023-08-21 10:02:25 -07:00
println ( hlog , " current.where = " , current . where , " : " , hr : : format ( " %p " , & current ) ) ;
2022-04-24 19:48:45 +02:00
2022-05-06 17:10:10 +02:00
int qgoals = isize ( goals ) ;
records [ 0 ] . resize ( qgoals , 0 ) ;
records [ 1 ] . resize ( qgoals , 0 ) ;
current_score . resize ( qgoals , 0 ) ;
2024-08-20 10:18:18 +02:00
int steps = 0 ;
2022-05-06 17:10:10 +02:00
/* start facing slightly to the right from the slope */
for ( auto b : { true , false } ) while ( true ) {
auto c = start ;
/* no treasures are known, which confuses goals */
dynamicval < bool > lop1 ( loaded_or_planned , true ) ;
dynamicval < bool > lop2 ( planning_mode , false ) ;
if ( c . tick ( this ) = = b ) break ;
2022-11-12 22:38:45 +01:00
start . heading_angle - = degree ;
2024-08-20 10:18:18 +02:00
steps + + ; if ( steps > 1080 ) break ;
2022-05-06 17:10:10 +02:00
}
2024-08-20 10:18:18 +02:00
if ( steps > 1080 ) println ( hlog , " warning: could not find a correct start.heading_angle " ) ;
2022-05-03 22:06:21 +02:00
if ( flags & nrlOrder ) {
sort ( triangles . begin ( ) , triangles . end ( ) , [ this ] ( triangledata a , triangledata b ) {
2022-11-12 22:38:45 +01:00
return atan2 ( spin ( 120. _deg ) * ( a . where - start . where ) ) < atan2 ( spin ( 120. _deg ) * ( b . where - start . where ) ) ;
2022-05-03 22:06:21 +02:00
} ) ;
for ( auto t : triangles ) println ( hlog , t . where ) ;
}
2022-05-06 17:10:10 +02:00
2022-04-24 19:48:45 +02:00
init_plan ( ) ;
2024-08-18 13:56:46 +02:00
2024-08-18 21:21:18 +02:00
for ( auto s : sublevels ) {
s - > init ( ) ;
for ( auto & t : s - > triangles ) triangles . push_back ( t ) ;
s - > triangles . clear ( ) ;
}
2022-04-24 19:48:45 +02:00
}
2022-05-03 11:28:31 +02:00
xy_float level : : get_xy_f ( hyperpoint h ) {
2022-05-03 11:53:08 +02:00
if ( flags & nrlPolar ) {
tie ( h [ 0 ] , h [ 1 ] ) = make_pair ( atan2 ( h [ 0 ] , h [ 1 ] ) , hypot ( h [ 0 ] , h [ 1 ] ) ) ;
ld bar = ( minx + maxx ) / 2 ;
2022-11-12 22:38:45 +01:00
cyclefix ( h [ 0 ] , bar ) ;
2022-05-03 11:53:08 +02:00
}
2022-05-03 11:28:31 +02:00
int tY = isize ( map_tiles ) ;
int tX = isize ( map_tiles [ 0 ] ) ;
ld rtx = ilerp ( minx , maxx , h [ 0 ] ) * tX ;
ld rty = ilerp ( miny , maxy , h [ 1 ] ) * tY ;
return { rtx , rty } ;
}
char level : : mapchar ( xy_int p ) {
auto x = p . first ;
auto y = p . second ;
int tY = isize ( map_tiles ) ;
int tX = isize ( map_tiles [ 0 ] ) ;
if ( x < 0 | | y < 0 | | x > = tX | | y > = tY ) return ' ! ' ;
return map_tiles [ y ] [ x ] ;
}
2022-04-24 19:48:45 +02:00
/* convert ASCII map coordinates to Heisenberg coordinates */
hyperpoint level : : mappt ( ld x , ld y , int s ) {
int tY = isize ( map_tiles ) ;
int tX = isize ( map_tiles [ 0 ] ) ;
x / = s ;
y / = s ;
hyperpoint h ;
h [ 0 ] = lerp ( minx , maxx , x / tX ) ;
h [ 1 ] = lerp ( miny , maxy , y / tY ) ;
if ( flags & nrlPolar )
tie ( h [ 0 ] , h [ 1 ] ) = make_pair ( h [ 1 ] * sin ( h [ 0 ] ) , h [ 1 ] * cos ( h [ 0 ] ) ) ;
h [ 2 ] = surface ( h ) ;
h [ 3 ] = 1 ;
return h ;
} ;
void level : : init_plan ( ) {
2022-11-12 22:38:45 +01:00
plan . emplace_back ( start . where , hpxy ( cos ( start . heading_angle + 90. _deg ) * 2 , sin ( start . heading_angle + 90. _deg ) * 2 ) ) ;
2022-04-24 19:48:45 +02:00
current = start ;
}
2022-04-30 12:01:18 +02:00
ld level : : safe_alt ( hyperpoint h , ld mul , ld mulx ) {
2022-04-24 19:48:45 +02:00
ld maxv = 0 ;
for ( int x : { - 1 , 0 , 1 } )
for ( int y : { - 1 , 0 , 1 } ) {
2023-01-30 01:20:12 +01:00
hyperpoint c = sym_to_used ( point31 ( x * .5 * scale * mulx , y * .5 * scale * mulx , 0 ) ) ;
2022-04-24 19:48:45 +02:00
hyperpoint j = rgpushxto0 ( h ) * c ;
maxv = max ( maxv , mul * ( surface ( j ) - j [ 2 ] ) ) ;
}
return maxv ;
}
2022-05-05 22:37:05 +02:00
bool stepped_display ;
2022-08-14 19:24:13 +02:00
int nilrider_tempo = 562 ;
int nilrider_shift = 2633 ;
2022-04-24 19:48:45 +02:00
void level : : draw_level ( const shiftmatrix & V ) {
2022-04-30 12:01:18 +02:00
int id = 0 ;
2022-05-06 17:10:10 +02:00
init_statues ( ) ;
2024-08-18 13:56:46 +02:00
init_shapes ( ) ;
init_textures ( ) ;
2022-05-06 17:10:10 +02:00
2022-04-30 12:01:18 +02:00
for ( auto & t : triangles ) {
bool gotit = current . collected_triangles & Flag ( id ) ;
id + + ;
if ( ! gotit ) {
for ( int i = 0 ; i < 6 ; i + + ) {
2022-08-14 19:24:13 +02:00
ld tim = current . timer * 1000 ;
tim - = nilrider_shift ;
tim / = nilrider_tempo ;
2023-01-30 01:25:40 +01:00
transmatrix spin = Id ;
if ( nilv : : model_used = = 0 ) spin = cspin ( 0 , 1 , tim * M_PI / 6 ) ;
2022-08-14 19:24:13 +02:00
tim = abs ( 0.2 * sin ( tim * M_PI ) ) ;
2023-01-30 01:25:40 +01:00
auto & poly = queuepoly ( V * rgpushxto0 ( t . where ) * cpush ( 2 , tim ) * spin , shMini [ i ] , t . colors [ i ] ) ;
2022-04-30 12:01:18 +02:00
poly . tinf = & floor_texture_vertices [ cgi . shFloor . id ] ;
ensure_vertex_number ( * poly . tinf , poly . cnt ) ;
}
}
2022-04-24 19:48:45 +02:00
}
if ( true ) {
auto & poly = queuepoly ( V , shCastle , 0xC02020FF ) ;
poly . tinf = & castle_tinf ;
castle_tinf . texture_id = castle_texture - > textureid ;
}
for ( auto st : statues ) queuepoly ( V * st . T , * st . shape , st . color ) ;
queuepoly ( V , shField , 0xFFFF00FF ) ;
2022-05-05 22:37:05 +02:00
if ( ! stepped_display ) {
auto & poly = queuepoly ( V , shFloor , 0xFFFFFFFF ) ; // 0xFFFFFFFF);
poly . tinf = & uniltinf ;
uniltinf . texture_id = unil_texture - > textureid ;
}
else {
auto & poly = queuepoly ( V , shStepFloor , 0xFFFFFFFF ) ; // 0xFFFFFFFF);
poly . tinf = & uniltinf_stepped ;
uniltinf_stepped . texture_id = unil_texture_stepped - > textureid ;
}
2022-04-24 19:48:45 +02:00
}
2022-05-06 13:16:20 +02:00
2024-08-18 13:56:46 +02:00
void level : : draw_level_rec ( const shiftmatrix & V ) {
draw_level ( V ) ;
for ( auto sub : sublevels ) sub - > draw_level_rec ( V ) ;
}
2022-05-06 19:51:46 +02:00
void cleanup_texture ( texture : : texture_data * & d ) {
if ( d ) delete d ;
d = nullptr ;
}
2022-05-06 13:16:20 +02:00
void cleanup_textures ( ) {
for ( auto l : all_levels ) {
2022-05-06 19:51:46 +02:00
cleanup_texture ( l - > unil_texture ) ;
cleanup_texture ( l - > unil_texture_stepped ) ;
2022-05-06 13:16:20 +02:00
}
2022-05-06 19:51:46 +02:00
println ( hlog , " CLEANUP texture " ) ;
cleanup_texture ( castle_texture ) ;
2022-05-06 13:16:20 +02:00
}
2024-08-20 10:18:54 +02:00
2024-08-20 19:13:28 +02:00
void load_level ( const string & fname , bool init ) {
2024-08-20 10:18:54 +02:00
fhstream f ( fname , " r " ) ;
2024-08-20 18:11:18 +02:00
if ( ! f . f ) throw hr_exception ( " could not open file " ) ;
2024-12-01 11:32:00 +01:00
level lev ( " Untitled " , ' 1 ' , nrlUserCreated , 0 , " " , - 1 , 1 , 1 , - 1 , { } , 0 , 0 , { } , rot_plane , { goal { 0x40FF40 , " Collect all the triangles " , basic_check ( 999 , 999 ) , " " , " " , award_stars ( 0 , 999 , 0 ) } } ) ;
2024-08-20 18:11:18 +02:00
lev . filename = fname ;
2024-08-20 10:18:54 +02:00
level * csub = & lev ;
string s ;
while ( true ) {
string s = scanline_noblank ( f ) ;
if ( s = = " " & & feof ( f . f ) ) break ;
if ( s = = " " ) continue ;
if ( s [ 0 ] = = ' # ' ) continue ;
auto pos = s . find ( ' ' ) ;
if ( pos = = string : : npos )
throw hr_exception ( " incorrect format, a line without space " ) ;
string cmd = s . substr ( 0 , pos ) ;
string param = s . substr ( pos + 1 ) ;
if ( cmd = = " NAME " ) { csub - > name = param ; }
else if ( cmd = = " DESC " ) { if ( csub - > longdesc ! = " " ) csub - > longdesc + = " \n \n " ; csub - > longdesc + = param ; }
else if ( cmd = = " BOUNDS " ) { if ( sscanf ( param . c_str ( ) , " %lf%lf%lf%lf " , & csub - > minx , & csub - > miny , & csub - > maxx , & csub - > maxy ) ! = 4 ) throw hr_exception ( " incorrect BOUNDS line " ) ; }
else if ( cmd = = " START " ) { if ( sscanf ( param . c_str ( ) , " %lf%lf " , & csub - > startx , & csub - > starty ) ! = 2 ) throw hr_exception ( " incorrect START line " ) ; }
else if ( cmd = = " MAP " ) csub - > map_tiles . push_back ( param ) ;
2024-08-20 11:05:18 +02:00
else if ( cmd = = " PIXEL " ) {
char label ; color_t col ;
if ( sscanf ( param . c_str ( ) , " %c%x " , & label , & col ) ! = 2 ) throw hr_exception ( " incorrect PIXEL line " ) ;
bcols [ label ] = col ;
}
else if ( cmd = = " BLOCK " ) {
if ( param . size ( ) ! = 1 ) throw hr_exception ( " incorrect BLOCK line " ) ;
auto & submap = submaps [ param [ 0 ] ] ;
for ( int y = 0 ; y < pixel_per_block ; y + + ) {
submap [ y ] = scanline_noblank ( f ) ;
if ( isize ( submap [ y ] ) ! = pixel_per_block ) throw hr_exception ( " incorrect length of a BLOCK line " ) ;
}
}
2024-08-20 10:18:54 +02:00
else if ( cmd = = " FUNCTION " ) {
if ( param = = " zero " ) csub - > surface = rot_plane ;
2024-08-20 10:44:57 +02:00
else if ( param = = " heisenberg " ) csub - > surface = f_heisenberg0 ;
else if ( param = = " well " ) csub - > surface = f_rot_well ;
else if ( param = = " longtrack " ) csub - > surface = long_x ;
else csub - > surface = [ param ] ( hyperpoint h ) - > ld {
exp_parser ep ;
ep . extra_params [ " x " ] = h [ 0 ] ;
ep . extra_params [ " y " ] = h [ 1 ] ;
ep . s = param ;
try {
return ep . rparse ( ) ;
}
catch ( hr_parse_exception & ) {
return 0 ;
}
} ;
2024-08-20 10:18:54 +02:00
}
else if ( cmd = = " LAYER " ) {
2024-08-20 11:05:43 +02:00
csub = new level ( lev ) ;
csub - > name = param ;
lev . sublevels . push_back ( csub ) ;
csub - > map_tiles = { } ;
2024-08-20 10:18:54 +02:00
}
}
if ( lev . startx < 0 | | lev . starty < 0 | | lev . starty > = isize ( lev . map_tiles ) | | lev . startx > = isize ( lev . map_tiles [ 0 ] ) )
throw hr_exception ( " start position incorrect " ) ;
auto all = lev . gen_layer_list ( ) ;
for ( auto & l : all ) {
if ( l - > map_tiles . empty ( ) ) throw hr_exception ( " no map " ) ;
if ( l - > map_tiles [ 0 ] . empty ( ) ) throw hr_exception ( " empty strings in map " ) ;
for ( auto & s : l - > map_tiles ) if ( isize ( s ) ! = isize ( l - > map_tiles [ 0 ] ) ) throw hr_exception ( " map is not rectangular " ) ;
if ( l - > minx = = l - > maxx ) throw hr_exception ( " bad map X dimensions " ) ;
if ( l - > miny = = l - > maxy ) throw hr_exception ( " bad map Y dimensions " ) ;
}
for ( auto & l : all_levels ) if ( l - > name = = lev . name ) {
if ( l - > flags & nrlUserCreated ) {
2024-08-20 10:33:31 +02:00
cgi . ext . erase ( " nillevel- " + l - > name ) ;
2024-08-20 10:18:54 +02:00
swap ( * l , lev ) ;
curlev = l ;
if ( on ) l - > init ( ) ;
return ;
}
else throw hr_exception ( " cannot use the same name as an official level " ) ;
}
2024-08-20 19:13:28 +02:00
if ( init ) {
curlev = new level ( lev ) ;
all_levels . emplace_back ( curlev ) ;
if ( on ) curlev - > init ( ) ;
}
2024-08-20 10:18:54 +02:00
}
2022-04-24 19:48:45 +02:00
}
2024-08-20 10:18:54 +02:00