2022-05-06 11:21:01 +00:00
# if NILRIDER
2022-05-28 16:48:38 +00:00
# define CUSTOM_CAPTION "Nil Rider 1.0"
2022-05-06 11:21:01 +00:00
# define MAXMDIM 4
# define CAP_INV 0
# define CAP_COMPLEX2 0
# define CAP_EDIT 0
2022-05-09 12:54:08 +00:00
# define CAP_TEXTURE 1
2022-05-06 11:21:01 +00:00
# define CAP_BT 0
# define CAP_SOLV 0
# define CAP_THREAD 0
# define CAP_RUG 0
# define CAP_SVG 0
# define CAP_TOUR 0
# define CAP_IRR 0
# define CAP_CRYSTAL 0
# define CAP_ARCM 0
# define CAP_HISTORY 0
# define CAP_STARTANIM 0
# define CAP_SAVE 0
# define CAP_TRANS 0
# ifdef BWEB
# include "../../hyperweb.cpp"
# else
# include "../../hyper.cpp"
# endif
# include "../simple-impossible.cpp"
# include "../rogueviz.cpp"
# endif
2022-04-24 17:48:45 +00:00
# include "nilrider.h"
# include "statues.cpp"
# include "timestamp.cpp"
# include "levels.cpp"
# include "level.cpp"
# include "planning.cpp"
2022-04-30 10:04:50 +00:00
# include "solver.cpp"
2022-05-01 14:45:18 +00:00
# include "save.cpp"
2022-04-24 17:48:45 +00:00
namespace nilrider {
2023-08-06 09:51:43 +00:00
multi : : config scfg_nilrider ;
2022-04-24 17:48:45 +00:00
/** is the game paused? */
bool paused = false ;
bool planning_mode = false ;
2022-05-01 14:42:38 +00:00
bool view_replay = false ;
2022-04-24 17:48:45 +00:00
int simulation_start_tick ;
2022-05-01 10:12:04 +00:00
ld aimspeed_key_x = 1 , aimspeed_key_y = 1 , aimspeed_mouse_x = 1 , aimspeed_mouse_y = 1 ;
2022-05-01 10:51:17 +00:00
vector < string > move_names = { " camera down " , " move left " , " camera up " , " move right " , " fine control " , " pause " , " reverse time " , " view simulation " , " menu " } ;
int reversals = 0 ;
2022-05-06 10:56:08 +00:00
bool loaded_or_planned = false ;
2022-05-01 10:51:17 +00:00
2022-04-24 17:48:45 +00:00
void frame ( ) {
2022-05-01 14:42:38 +00:00
if ( planning_mode & & ! view_replay ) return ;
2022-04-24 17:48:45 +00:00
shiftmatrix V = ggmatrix ( cwt . at ) ;
curlev - > draw_level ( V ) ;
curlev - > current . draw_unilcycle ( V ) ;
}
2022-05-06 12:16:39 +00:00
bool crash_sound = true ;
2022-05-28 16:49:29 +00:00
bool running ;
bool backing ;
2022-08-14 17:24:13 +00:00
/* land for music */
eLand music_nilrider = eLand ( 400 ) ;
eLand music_nilrider_back = eLand ( 401 ) ;
eLand music_nilrider_paused = eLand ( 402 ) ;
eLand music_nilrider_planning = eLand ( 403 ) ;
eLand music_nilrider_nonrunning = eLand ( 404 ) ;
2022-05-28 16:49:29 +00:00
void sync_music ( eLand l ) {
2022-08-14 17:24:13 +00:00
musicpos [ music_nilrider ] = zgmod ( curlev - > current . timer * 1000 , musiclength [ music_nilrider ] ) ;
musicpos [ music_nilrider_back ] = zgmod ( - curlev - > current . timer * 1000 , musiclength [ music_nilrider_back ] ) ;
2022-05-28 16:49:29 +00:00
}
2022-05-06 12:16:39 +00:00
2022-04-24 17:48:45 +00:00
bool turn ( int delta ) {
2022-05-01 14:42:38 +00:00
if ( planning_mode & & ! view_replay ) return false ;
2022-05-01 10:12:04 +00:00
2023-08-06 09:51:43 +00:00
multi : : get_actions ( scfg_nilrider ) ;
2022-05-01 10:51:17 +00:00
auto & a = multi : : actionspressed ;
auto & la = multi : : lactionpressed ;
2022-04-24 17:48:45 +00:00
2022-05-01 10:51:17 +00:00
ld mul = 1 ;
if ( a [ 16 + 4 ] ) mul / = 5 ;
if ( a [ 16 + 3 ] & & ! paused ) curlev - > current . heading_angle - = aimspeed_key_x * mul * delta / 1000. ;
if ( a [ 16 + 1 ] & & ! paused ) curlev - > current . heading_angle + = aimspeed_key_x * mul * delta / 1000. ;
if ( a [ 16 + 2 ] & & ! paused ) min_gfx_slope - = aimspeed_key_y * mul * delta / 1000. ;
if ( a [ 16 + 0 ] & & ! paused ) min_gfx_slope + = aimspeed_key_y * mul * delta / 1000. ;
2022-05-01 10:12:04 +00:00
curlev - > current . heading_angle - = aimspeed_mouse_x * mouseaim_x * mul ;
min_gfx_slope + = aimspeed_mouse_y * mouseaim_y * mul ;
2022-04-24 17:48:45 +00:00
# if CAP_VR
if ( vrhr : : active ( ) ) {
2022-05-01 10:12:04 +00:00
curlev - > current . heading_angle - = aimspeed_mouse_x * vrhr : : vraim_x * mul * delta / 400 ;
min_gfx_slope - = aimspeed_mouse_y * vrhr : : vraim_y * mul * delta / 400 ;
2022-04-24 17:48:45 +00:00
}
# endif
2022-11-12 21:38:45 +00:00
if ( min_gfx_slope < - 90. _deg ) min_gfx_slope = - 90. _deg ;
if ( min_gfx_slope > + 90. _deg ) min_gfx_slope = + 90. _deg ;
2022-05-28 16:49:29 +00:00
backing = false ;
2022-05-01 10:51:17 +00:00
if ( a [ 16 + 6 ] ) {
if ( ! la [ 16 + 6 ] ) reversals + + ;
if ( planning_mode )
simulation_start_tick + = 2 * delta ;
else for ( int i = 0 ; i < delta ; i + + ) {
if ( isize ( curlev - > history ) > 1 ) {
backing = true ;
curlev - > history . pop_back ( ) ;
curlev - > current = curlev - > history . back ( ) ;
2022-05-06 12:16:39 +00:00
crash_sound = true ;
2022-05-01 10:51:17 +00:00
}
else {
reversals = 0 ;
2022-05-06 10:56:08 +00:00
loaded_or_planned = false ;
2022-05-06 12:16:39 +00:00
crash_sound = true ;
2022-05-01 10:51:17 +00:00
}
}
}
2022-05-06 12:16:39 +00:00
if ( ! paused & & ! view_replay & & ! backing ) {
auto t = curlev - > current . collected_triangles ;
bool fail = false ;
for ( int i = 0 ; i < delta ; i + + ) {
curlev - > history . push_back ( curlev - > current ) ;
curlev - > current . be_consistent ( ) ;
bool b = curlev - > current . tick ( curlev ) ;
2022-05-28 16:49:29 +00:00
running = b ;
2022-05-06 12:31:50 +00:00
if ( ! b ) {
curlev - > history . pop_back ( ) ;
fail = true ;
2022-05-06 19:07:57 +00:00
break ;
2022-05-06 12:31:50 +00:00
}
2022-05-06 12:16:39 +00:00
}
if ( t ! = curlev - > current . collected_triangles )
playSound ( cwt . at , " pickup-gold " ) ;
if ( fail & & crash_sound ) {
char ch = curlev - > mapchar ( curlev - > current . where ) ;
if ( ch = = ' r ' ) {
playSound ( cwt . at , " closegate " ) ;
crash_sound = false ;
}
if ( ch = = ' ! ' ) {
playSound ( cwt . at , " seen-air " ) ;
crash_sound = false ;
}
}
2022-04-24 17:48:45 +00:00
}
if ( ! paused ) curlev - > current . centerview ( curlev ) ;
return false ;
}
void main_menu ( ) ;
2022-05-01 10:51:17 +00:00
# define PSEUDOKEY_PAUSE 2511
# define PSEUDOKEY_SIM 2512
2022-05-01 14:42:38 +00:00
void toggle_replay ( ) {
view_replay = ! view_replay ;
paused = false ;
simulation_start_tick = ticks ;
if ( ! view_replay & & ! planning_mode ) {
paused = true ;
curlev - > current = curlev - > history . back ( ) ;
}
}
2022-04-24 17:48:45 +00:00
void run ( ) {
2022-05-06 18:28:08 +00:00
cmode = sm : : PANNING | sm : : NORMAL ;
2022-04-24 17:48:45 +00:00
clearMessages ( ) ;
dialog : : init ( ) ;
2022-05-01 14:42:38 +00:00
if ( view_replay & & ! paused ) {
2022-04-24 17:48:45 +00:00
int ttick = gmod ( ticks - simulation_start_tick , isize ( curlev - > history ) ) ;
curlev - > current = curlev - > history [ ttick ] ;
curlev - > current . centerview ( curlev ) ;
}
2022-05-01 14:42:38 +00:00
if ( planning_mode & & ! view_replay )
2022-04-30 10:02:30 +00:00
cmode | = sm : : SHOWCURSOR ;
2022-05-01 10:12:04 +00:00
if ( aimspeed_mouse_x = = 0 & & aimspeed_mouse_y = = 0 )
cmode | = sm : : SHOWCURSOR ;
2022-07-05 14:03:12 +00:00
gamescreen ( ) ;
2022-05-01 14:42:38 +00:00
if ( planning_mode & & ! view_replay ) {
2022-04-24 17:48:45 +00:00
curlev - > draw_planning_screen ( ) ;
if ( ! holdmouse ) {
auto t0 = SDL_GetTicks ( ) ;
while ( SDL_GetTicks ( ) < t0 + 100 ) {
if ( ! curlev - > simulate ( ) ) break ;
}
}
}
2022-05-06 12:31:50 +00:00
curlev - > current . draw_instruments ( curlev ) ;
2022-04-24 17:48:45 +00:00
if ( paused & & ! planning_mode ) {
displayButton ( current_display - > xcenter , current_display - > ycenter , mousing ? XLAT ( " paused -- click to unpause " ) : XLAT ( " paused -- press p to continue " ) , ' p ' , 8 ) ;
}
int x = vid . fsize ;
2022-05-01 10:51:17 +00:00
auto show_button = [ & ] ( int c , string s , color_t col = dialog : : dialogcolor ) {
2022-04-24 17:48:45 +00:00
if ( displayButtonS ( x , vid . yres - vid . fsize , s , col , 0 , vid . fsize ) )
getcstat = c ;
x + = textwidth ( vid . fsize , s ) + vid . fsize ;
} ;
2022-05-01 14:42:38 +00:00
if ( planning_mode & & ! view_replay ) {
2022-04-24 17:48:45 +00:00
for ( auto & b : buttons ) show_button ( b . first , b . second , planmode = = b . first ? 0xFFD500 : dialog : : dialogcolor ) ;
2022-05-01 10:51:17 +00:00
show_button ( PSEUDOKEY_SIM , " simulation " ) ;
2022-04-24 17:48:45 +00:00
}
2022-05-01 14:42:38 +00:00
bool pause_av = view_replay | | ! planning_mode ;
if ( pause_av ) {
show_button ( PSEUDOKEY_SIM , planning_mode ? " return " : " replay " , ( view_replay & & ! planning_mode ) ? 0xFF0000 : dialog : : dialogcolor ) ;
2022-05-01 10:51:17 +00:00
show_button ( PSEUDOKEY_PAUSE , " pause " , paused ? 0xFF0000 : dialog : : dialogcolor ) ;
2022-04-24 17:48:45 +00:00
}
2022-05-01 10:51:17 +00:00
show_button ( PSEUDOKEY_MENU , " menu " ) ;
2022-04-24 17:48:45 +00:00
2022-05-01 10:51:17 +00:00
dialog : : add_key_action ( PSEUDOKEY_MENU , [ ] {
2022-05-06 16:51:04 +00:00
if ( curlev - > current . timer ) paused = true ;
2022-09-24 07:13:00 +00:00
game_keys_scroll = true ;
2022-04-24 17:48:45 +00:00
pushScreen ( main_menu ) ;
} ) ;
2022-05-01 10:51:17 +00:00
if ( pause_av ) dialog : : add_key_action ( PSEUDOKEY_PAUSE , [ ] {
2022-04-24 17:48:45 +00:00
paused = ! paused ;
2022-09-24 07:13:00 +00:00
game_keys_scroll = true ;
2022-05-01 14:42:38 +00:00
if ( view_replay & & ! paused )
2022-05-06 12:31:50 +00:00
simulation_start_tick = ticks - curlev - > current . timer * tps ;
2022-04-24 17:48:45 +00:00
} ) ;
dialog : : add_key_action ( ' - ' , [ ] {
paused = false ;
} ) ;
2022-05-01 14:42:38 +00:00
dialog : : add_key_action ( PSEUDOKEY_SIM , toggle_replay ) ;
2022-04-24 17:48:45 +00:00
dialog : : display ( ) ;
2022-05-01 10:51:17 +00:00
2024-05-26 18:22:29 +00:00
int * t = scfg_nilrider . keyaction ;
2022-05-01 10:51:17 +00:00
for ( int i = 1 ; i < 512 ; i + + ) {
auto & ka = dialog : : key_actions ;
if ( t [ i ] = = 16 + 5 ) ka [ i ] = ka [ PSEUDOKEY_PAUSE ] ;
if ( t [ i ] = = 16 + 7 ) ka [ i ] = ka [ PSEUDOKEY_SIM ] ;
if ( t [ i ] = = 16 + 8 ) ka [ i ] = ka [ PSEUDOKEY_MENU ] ;
}
2022-04-24 17:48:45 +00:00
keyhandler = [ ] ( int sym , int uni ) {
if ( paused ) handlePanning ( sym , uni ) ;
2022-05-01 14:42:38 +00:00
if ( planning_mode & & ! view_replay & & curlev - > handle_planning ( sym , uni ) ) return ;
2022-04-24 17:48:45 +00:00
dialog : : handleNavigation ( sym , uni ) ;
} ;
}
2022-05-06 10:56:08 +00:00
void clear_path ( level * l ) {
l - > history . clear ( ) ;
l - > current = l - > start ;
l - > history . push_back ( l - > start ) ;
paused = false ;
reversals = 0 ;
loaded_or_planned = false ;
2022-05-06 12:16:39 +00:00
crash_sound = true ;
2022-05-06 10:56:08 +00:00
}
2022-04-24 17:48:45 +00:00
void pick_level ( ) {
clearMessages ( ) ;
dialog : : init ( XLAT ( " select the track " ) , 0xC0C0FFFF , 150 , 100 ) ;
for ( auto l : all_levels ) {
dialog : : addItem ( l - > name , l - > hotkey ) ;
dialog : : add_action ( [ l ] {
curlev = l ;
recompute_plan_transform = true ;
l - > init ( ) ;
2022-05-06 10:56:08 +00:00
clear_path ( l ) ;
2022-04-24 17:48:45 +00:00
popScreen ( ) ;
} ) ;
}
dialog : : addBreak ( 100 ) ;
dialog : : addBack ( ) ;
dialog : : display ( ) ;
}
void pick_game ( ) {
clearMessages ( ) ;
2022-05-06 16:50:47 +00:00
dialog : : init ( ) ;
poly_outline = 0xFF ;
dialog : : addBigItem ( curlev - > name , ' t ' ) ;
2022-05-06 14:49:37 +00:00
dialog : : addBreak ( 50 ) ;
dialog : : addHelp ( curlev - > longdesc ) ;
int gid = 0 ;
for ( auto & g : curlev - > goals ) {
dialog : : addBreak ( 50 ) ;
auto man = curlev - > records [ 0 ] [ gid ] ;
auto plan = curlev - > records [ 1 ] [ gid ] ;
if ( man & & plan )
dialog : : addInfo ( " manual: " + format_timer ( man ) + " planning: " + format_timer ( plan ) , g . color ) ;
else if ( man )
dialog : : addInfo ( " manual: " + format_timer ( man ) , g . color ) ;
else if ( plan )
dialog : : addInfo ( " planning: " + format_timer ( plan ) , g . color ) ;
else
dialog : : addInfo ( " goal not obtained: " , g . color ) ;
dialog : : addBreak ( 50 ) ;
dialog : : addHelp ( g . desc ) ;
gid + + ;
}
2022-04-24 17:48:45 +00:00
dialog : : addBreak ( 100 ) ;
2022-05-06 16:50:47 +00:00
dialog : : addItem ( " change the track " , ' t ' ) ;
dialog : : add_action_push ( pick_level ) ;
dialog : : addBreak ( 100 ) ;
add_edit ( planning_mode ) ;
2023-08-22 18:11:46 +00:00
dialog : : addItem ( XLAT ( " play this track " ) , SDLK_ESCAPE ) ;
dialog : : addItem ( XLAT ( " quit Nil Rider " ) , ' q ' ) ;
dialog : : add_action ( [ ] { quitmainloop = true ; } ) ;
2022-04-24 17:48:45 +00:00
dialog : : display ( ) ;
}
2022-05-06 00:53:36 +00:00
void nil_set_geodesic ( ) {
pmodel = mdGeodesic ;
nisot : : geodesic_movement = true ;
popScreen ( ) ;
}
void nil_set_perspective ( ) {
pmodel = mdPerspective ;
nisot : : geodesic_movement = false ;
pconf . rotational_nil = 0 ;
}
void nil_projection ( ) {
dialog : : init ( XLAT ( " projection of Nil " ) , 0xC0C0FFFF , 150 , 100 ) ;
dialog : : addBoolItem ( " geodesics " , pmodel = = mdGeodesic , ' g ' ) ;
dialog : : add_action ( [ ] { popScreen ( ) ; nil_set_geodesic ( ) ; } ) ;
dialog : : addInfo ( " In this mode, the light is assumed to travel along the geodesics (the shortest paths in Nil). " ) ;
dialog : : addBreak ( 100 ) ;
dialog : : addBoolItem ( " constant direction " , pmodel = = mdPerspective , ' c ' ) ;
dialog : : add_action ( [ ] { popScreen ( ) ; nil_set_perspective ( ) ; } ) ;
dialog : : addInfo ( " In this mode, the light is assumed to travel along the lines of constant direction. " ) ;
dialog : : addBreak ( 100 ) ;
dialog : : addBack ( ) ;
dialog : : display ( ) ;
}
2022-04-24 17:48:45 +00:00
void settings ( ) {
dialog : : init ( XLAT ( " settings " ) , 0xC0C0FFFF , 150 , 100 ) ;
2022-05-01 10:12:04 +00:00
add_edit ( aimspeed_key_x ) ;
add_edit ( aimspeed_key_y ) ;
add_edit ( aimspeed_mouse_x ) ;
add_edit ( aimspeed_mouse_y ) ;
2022-05-01 14:53:50 +00:00
add_edit ( whrad ) ;
add_edit ( whdist ) ;
add_edit ( min_gfx_slope ) ;
2022-05-05 20:37:05 +00:00
add_edit ( stepped_display ) ;
2022-05-06 00:53:36 +00:00
dialog : : addItem ( " projection " , ' P ' ) ;
dialog : : add_action_push ( nil_projection ) ;
2022-05-01 10:51:17 +00:00
dialog : : addItem ( " configure keys " , ' k ' ) ;
2023-08-06 09:51:43 +00:00
dialog : : add_action_push ( multi : : get_key_configurer ( 1 , move_names , " Nilrider keys " , scfg_nilrider ) ) ;
2022-08-14 17:55:25 +00:00
# if CAP_AUDIO
add_edit ( effvolume ) ;
add_edit ( musicvolume ) ;
# endif
2022-05-09 07:40:35 +00:00
# if CAP_VR
2022-05-06 18:28:08 +00:00
vrhr : : enable_button ( ) ;
vrhr : : reference_button ( ) ;
2022-05-09 07:40:35 +00:00
# endif
2022-05-06 18:28:08 +00:00
2022-04-24 17:48:45 +00:00
dialog : : addItem ( " RogueViz settings " , ' r ' ) ;
dialog : : add_key_action ( ' r ' , [ ] {
pushScreen ( showSettings ) ;
} ) ;
2022-08-20 14:44:41 +00:00
# if CAP_FILES && !ISWEB
dialog : : addItem ( " save the current config " , ' s ' ) ;
dialog : : add_action ( [ ] {
dynamicval < eGeometry > g ( geometry , gNormal ) ;
saveConfig ( ) ;
} ) ;
# endif
2022-04-24 17:48:45 +00:00
dialog : : addBreak ( 100 ) ;
dialog : : addBack ( ) ;
2022-05-06 00:53:36 +00:00
dialog : : display ( ) ;
2022-04-24 17:48:45 +00:00
}
2022-05-02 01:38:20 +00:00
bool deleting = false ;
template < class T , class U > void replays_of_type ( vector < T > & v , const U & loader ) {
int i = 0 ;
for ( auto & r : v ) {
dialog : : addItem ( r . name , ' a ' ) ;
dialog : : add_action ( [ & v , i , loader ] {
if ( deleting ) {
dialog : : push_confirm_dialog (
[ & , i ] { v . erase ( v . begin ( ) + i ) ; save ( ) ; } ,
" Are you sure you want to delete ' " + v [ i ] . name + " '? "
) ;
}
else loader ( v [ i ] ) ;
} ) ;
i + + ;
}
}
2022-05-09 13:09:02 +00:00
# if CAP_SAVE
2022-05-02 01:38:20 +00:00
void replays ( ) {
dialog : : init ( XLAT ( planning_mode ? " saved plans " : " replays " ) , 0xC0C0FFFF , 150 , 100 ) ;
if ( ! planning_mode ) replays_of_type ( curlev - > manual_replays , [ ] ( manual_replay & r ) {
view_replay = false ;
curlev - > history . clear ( ) ;
auto & current = curlev - > current ;
current = curlev - > start ;
2022-05-06 10:56:08 +00:00
loaded_or_planned = true ;
2022-05-02 01:38:20 +00:00
for ( auto h : r . headings ) {
current . heading_angle = int_to_heading ( h ) ;
curlev - > history . push_back ( current ) ;
if ( ! current . tick ( curlev ) ) break ;
}
toggle_replay ( ) ;
popScreen ( ) ;
} ) ;
if ( planning_mode ) replays_of_type ( curlev - > plan_replays , [ ] ( plan_replay & r ) {
view_replay = false ;
curlev - > history . clear ( ) ;
curlev - > plan = r . plan ;
popScreen ( ) ;
} ) ;
dialog : : addBoolItem_action ( " delete " , deleting , ' X ' ) ;
dialog : : addBack ( ) ;
dialog : : display ( ) ;
}
void pop_and_push_replays ( ) {
deleting = false ;
popScreen ( ) ;
pushScreen ( replays ) ;
}
2022-05-09 13:09:02 +00:00
# endif
2022-05-02 01:38:20 +00:00
2023-08-07 15:16:44 +00:00
reaction_t on_quit = [ ] { quitmainloop = true ; } ;
2022-04-24 17:48:45 +00:00
2022-08-14 17:24:39 +00:00
void restart ( ) {
clear_path ( curlev ) ;
}
2022-04-24 17:48:45 +00:00
void main_menu ( ) {
clearMessages ( ) ;
2022-05-06 16:51:18 +00:00
poly_outline = 0xFF ;
2022-04-24 17:48:45 +00:00
dialog : : init ( XLAT ( " Nil Rider " ) , 0xC0C0FFFF , 150 , 100 ) ;
dialog : : addItem ( " continue " , ' c ' ) ;
dialog : : add_action ( popScreen ) ;
if ( ! planning_mode ) {
dialog : : addItem ( " restart " , ' r ' ) ;
dialog : : add_action ( [ ] {
2022-05-06 10:56:08 +00:00
clear_path ( curlev ) ;
2022-04-24 17:48:45 +00:00
popScreen ( ) ;
} ) ;
dialog : : addItem ( " view the replay " , ' v ' ) ;
2022-05-01 14:42:38 +00:00
dialog : : add_action ( toggle_replay ) ;
2022-04-24 17:48:45 +00:00
2022-05-09 13:09:02 +00:00
# if CAP_SAVE
2022-05-01 14:45:18 +00:00
dialog : : addItem ( " save the replay " , ' s ' ) ;
2022-04-24 17:48:45 +00:00
dialog : : add_action ( [ ] {
2022-05-01 14:45:18 +00:00
vector < int > ang ;
for ( auto & h : curlev - > history ) ang . push_back ( heading_to_int ( h . heading_angle ) ) ;
curlev - > manual_replays . emplace_back ( manual_replay { new_replay_name ( ) , std : : move ( ang ) } ) ;
save ( ) ;
2022-04-24 17:48:45 +00:00
} ) ;
2022-05-02 01:38:20 +00:00
dialog : : addItem ( " load a replay " , ' l ' ) ;
dialog : : add_action ( pop_and_push_replays ) ;
2022-05-09 13:09:02 +00:00
# endif
2022-04-24 17:48:45 +00:00
}
else {
2022-05-09 13:09:02 +00:00
# if CAP_SAVE
2022-04-24 17:48:45 +00:00
dialog : : addItem ( " save this plan " , ' s ' ) ;
dialog : : add_action ( [ ] {
2022-05-01 14:45:18 +00:00
curlev - > plan_replays . emplace_back ( plan_replay { new_replay_name ( ) , curlev - > plan } ) ;
save ( ) ;
2022-04-24 17:48:45 +00:00
} ) ;
2022-05-02 01:38:20 +00:00
dialog : : addItem ( " load a plan " , ' l ' ) ;
dialog : : add_action ( pop_and_push_replays ) ;
2022-05-09 13:09:02 +00:00
# endif
2022-04-24 17:48:45 +00:00
}
2022-05-06 14:49:37 +00:00
dialog : : addItem ( " track / mode / goals " , ' t ' ) ;
2022-04-24 17:48:45 +00:00
dialog : : add_action_push ( pick_game ) ;
2022-05-06 14:49:37 +00:00
dialog : : addItem ( " change settings " , ' o ' ) ;
2022-04-24 17:48:45 +00:00
dialog : : add_action_push ( settings ) ;
2022-05-09 12:45:57 +00:00
# if CAP_VIDEO
dialog : : addItem ( " record video " , ' v ' ) ;
dialog : : add_action ( [ ] {
dialog : : openFileDialog ( anims : : videofile , XLAT ( " record to video file " ) ,
" .mp4 " , [ ] {
anims : : period = isize ( curlev - > history ) ;
anims : : noframes = anims : : period * 60 / 1000 ;
int a = addHook ( anims : : hooks_anim , 100 , [ ] {
int ttick = ticks % isize ( curlev - > history ) ;
curlev - > current = curlev - > history [ ttick ] ;
curlev - > current . centerview ( curlev ) ;
anims : : moved ( ) ;
} ) ;
int af = addHook ( hooks_frame , 100 , [ ] {
int ttick = ticks % isize ( curlev - > history ) ;
curlev - > current = curlev - > history [ ttick ] ;
if ( planning_mode & & ! view_replay ) curlev - > draw_planning_screen ( ) ;
} ) ;
bool b = anims : : record_video_std ( ) ;
delHook ( anims : : hooks_anim , a ) ;
delHook ( hooks_frame , af ) ;
return b ;
} ) ;
} ) ;
# endif
2022-04-24 17:48:45 +00:00
dialog : : addItem ( " quit " , ' q ' ) ;
dialog : : add_action ( [ ] {
on_quit ( ) ;
} ) ;
dialog : : display ( ) ;
}
bool on ;
2022-05-01 10:51:17 +00:00
void change_default_key ( int key , int val ) {
2024-05-26 18:22:29 +00:00
int * t = scfg_nilrider . keyaction ;
2022-05-01 10:51:17 +00:00
t [ key ] = val ;
}
void nilrider_keys ( ) {
2023-08-06 09:51:43 +00:00
clear_config ( scfg_nilrider ) ;
2022-05-01 10:51:17 +00:00
change_default_key ( ' s ' , 16 + 0 ) ;
change_default_key ( ' a ' , 16 + 1 ) ;
change_default_key ( ' w ' , 16 + 2 ) ;
change_default_key ( ' d ' , 16 + 3 ) ;
2022-08-14 17:24:24 +00:00
# if CAP_SDL2
change_default_key ( SDL_SCANCODE_LCTRL , 16 + 4 ) ;
# else
2022-05-01 10:51:17 +00:00
change_default_key ( SDLK_LCTRL , 16 + 4 ) ;
2022-08-14 17:24:24 +00:00
# endif
2022-05-01 10:51:17 +00:00
change_default_key ( ' p ' , 16 + 5 ) ;
change_default_key ( ' b ' , 16 + 6 ) ;
change_default_key ( ' r ' , 16 + 7 ) ;
change_default_key ( ' v ' , 16 + 8 ) ;
2023-08-06 09:51:43 +00:00
sconfig_savers ( scfg_nilrider , " nilrider " ) ;
2022-05-01 10:51:17 +00:00
}
2022-05-28 16:49:29 +00:00
bool nilrider_music ( eLand & l ) {
if ( planning_mode & & ! view_replay )
2022-08-14 17:24:13 +00:00
l = music_nilrider_planning ;
2022-05-28 16:49:29 +00:00
else if ( paused )
2022-08-14 17:24:13 +00:00
l = music_nilrider_paused ;
2022-05-28 16:49:29 +00:00
else if ( ! running )
2022-08-14 17:24:13 +00:00
l = music_nilrider_nonrunning ;
2022-05-28 16:49:29 +00:00
else if ( backing )
2022-08-14 17:24:13 +00:00
l = music_nilrider_back ;
else l = music_nilrider ;
2022-05-28 16:49:29 +00:00
return false ;
}
2023-08-06 20:17:20 +00:00
local_parameter_set lps_nilrider ( " nilrider: " ) ;
void default_settings ( ) {
lps_add ( lps_nilrider , vid . cells_drawn_limit , 1 ) ;
2024-05-26 18:22:29 +00:00
lps_add ( lps_nilrider , ccolor : : plain . ctab [ 0 ] , 0 ) ;
2023-08-06 20:17:20 +00:00
lps_add ( lps_nilrider , smooth_scrolling , true ) ;
2023-08-07 15:59:50 +00:00
lps_add ( lps_nilrider , mapeditor : : drawplayer , false ) ;
2023-08-06 20:17:20 +00:00
lps_add ( lps_nilrider , backcolor , 0xC0C0FFFF ) ;
lps_add ( lps_nilrider , logfog , 1 ) ;
2024-05-24 18:57:53 +00:00
lps_add ( lps_nilrider , ccolor : : which , & ccolor : : plain ) ;
2024-05-26 18:42:47 +00:00
lps_add ( lps_nilrider , ccolor : : rwalls , 0 ) ;
2023-08-06 20:17:20 +00:00
# if CAP_VR
2023-08-08 09:50:55 +00:00
lps_add ( lps_nilrider , vrhr : : hsm , vrhr : : eHeadset : : reference ) ;
lps_add ( lps_nilrider , vrhr : : eyes , vrhr : : eEyes : : equidistant ) ;
2023-08-06 20:17:20 +00:00
lps_add ( lps_nilrider , vrhr : : absolute_unit_in_meters , 6 ) ;
# endif
}
2022-04-24 17:48:45 +00:00
void initialize ( ) {
2022-05-02 01:38:20 +00:00
load ( ) ;
2022-05-01 10:51:17 +00:00
nilrider_keys ( ) ;
2022-04-24 17:48:45 +00:00
check_cgi ( ) ;
cgi . prepare_shapes ( ) ;
init_statues ( ) ;
curlev - > init ( ) ;
2024-05-26 18:22:29 +00:00
param_enum ( planning_mode , " nil_planning " , false )
2022-04-24 17:48:45 +00:00
- > editable ( { { " manual " , " control the unicycle manually " } , { " planning " , " try to plan the optimal route! " } } , " game mode " , ' p ' ) ;
2024-05-26 18:22:29 +00:00
param_enum ( stepped_display , " stepped_display " , false )
2022-05-05 20:37:05 +00:00
- > editable ( { { " smooth " , " ride on a smooth surface " } , { " blocky " , " makes slopes more visible -- actual physics are not affected " } } , " game mode " , ' s ' ) ;
2022-08-14 17:24:13 +00:00
param_i ( nilrider_tempo , " nilrider_tempo " ) ;
param_i ( nilrider_shift , " nilrider_shift " ) ;
2022-04-24 17:48:45 +00:00
rv_hook ( hooks_frame , 100 , frame ) ;
rv_hook ( shmup : : hooks_turn , 100 , turn ) ;
2022-05-06 11:16:20 +00:00
rv_hook ( hooks_resetGL , 100 , cleanup_textures ) ;
2022-05-28 16:49:29 +00:00
rv_hook ( hooks_music , 100 , nilrider_music ) ;
rv_hook ( hooks_sync_music , 100 , sync_music ) ;
2022-04-24 17:48:45 +00:00
on = true ;
on_cleanup_or_next ( [ ] { on = false ; } ) ;
pushScreen ( run ) ;
}
2022-05-06 00:53:55 +00:00
void initialize_all ( ) {
showstartmenu = false ;
stop_game ( ) ;
geometry = gNil ;
2022-05-06 10:14:18 +00:00
variation = eVariation : : pure ;
2022-05-06 00:53:55 +00:00
nil_set_geodesic ( ) ;
enable_canvas ( ) ;
2023-08-07 15:59:50 +00:00
lps_enable ( & lps_nilrider ) ;
2022-05-06 00:53:55 +00:00
initialize ( ) ;
2022-05-06 16:50:47 +00:00
poly_outline = 0xFF ;
pushScreen ( pick_game ) ;
2023-08-06 20:17:20 +00:00
start_game ( ) ;
2022-05-06 00:53:55 +00:00
}
2022-05-01 14:42:38 +00:00
auto celldemo = arg : : add3 ( " -unilcycle " , initialize ) + arg : : add3 ( " -unilplan " , [ ] { planning_mode = true ; } ) + arg : : add3 ( " -viewsim " , [ ] { view_replay = true ; } )
2022-04-24 17:48:45 +00:00
+ arg : : add3 ( " -oqc " , [ ] { on_quit = popScreenAll ; } )
2022-05-03 20:08:17 +00:00
+ arg : : add3 ( " -nilsolve-set " , [ ] {
arg : : shift ( ) ; solver_unit = arg : : argf ( ) ;
arg : : shift ( ) ; nospeed = arg : : argi ( ) ;
arg : : shift ( ) ; goal_id = arg : : argi ( ) ;
curlev - > solve ( ) ; } )
2022-04-30 10:04:50 +00:00
+ arg : : add3 ( " -nilsolve " , [ ] { curlev - > solve ( ) ; } )
2022-05-06 00:53:36 +00:00
+ arg : : add3 ( " -nilgeo " , nil_set_geodesic )
+ arg : : add3 ( " -nilper " , nil_set_perspective )
2022-05-06 00:53:55 +00:00
+ arg : : add3 ( " -nilrider " , initialize_all )
2022-05-06 19:08:15 +00:00
+ arg : : add3 ( " -nilrider-q " , [ ] { arg : : shift ( ) ; reduce_quality = arg : : argi ( ) ; } )
2022-05-01 10:12:04 +00:00
+ addHook ( hooks_configfile , 100 , [ ] {
param_f ( aimspeed_key_x , " nilrider_key_x " )
- > editable ( - 5 , 5 , 0.1 , " navigation sensitivity (keyboard) " , " press Left/Right to navigate (lCtrl to fine-tune) " , ' n ' ) ;
param_f ( aimspeed_key_y , " nilrider_key_y " )
- > editable ( - 5 , 5 , 0.1 , " camera sensitivity (keyboard) " , " press Up/Down to set the camera angle (lCtrl to fine-tune) " , ' c ' ) ;
param_f ( aimspeed_mouse_x , " nilrider_mouse_x " )
- > editable ( - 5 , 5 , 0.1 , " navigation sensitivity (mouse/vr) " , " move mouse Left/Right to navigate (lCtrl to fine-tune) " , ' N ' ) ;
param_f ( aimspeed_mouse_y , " nilrider_mouse_y " )
- > editable ( - 5 , 5 , 0.1 , " camera sensitivity (mouse/vr) " , " move mouse Up/Down to set the camera angle (lCtrl to fine-tune) " , ' C ' ) ;
2022-05-01 14:53:50 +00:00
param_f ( whrad , " nilrider_radius " )
- > editable ( 0 , 0.5 , 0.01 , " wheel radius " , " note: this parameter is just visual, it does not affect the physics in any way " , ' w ' ) ;
param_f ( whdist , " nilrider_dist " )
2022-05-05 23:36:55 +00:00
- > editable ( 0 , 5 , 0.05 , " camera distance " , " how far is the unicycle from the camera " , ' d ' )
- > set_reaction ( [ ] { curlev - > current . centerview ( curlev ) ; } ) ;
2022-05-01 14:53:50 +00:00
param_f ( min_gfx_slope , " min_gfx_slope " )
2022-11-12 21:38:45 +00:00
- > editable ( - 90. _deg , 90. _deg , degree , " min camera slope " , " affected by up/down " , ' m ' ) ;
2022-05-01 10:12:04 +00:00
} )
2022-04-24 17:48:45 +00:00
+ arg : : add3 ( " -fullsim " , [ ] {
/* for animations */
popScreenAll ( ) ;
rv_hook ( anims : : hooks_anim , 100 , [ ] {
int ttick = ticks % isize ( curlev - > history ) ;
curlev - > current = curlev - > history [ ttick ] ;
curlev - > current . centerview ( curlev ) ;
anims : : moved ( ) ;
} ) ;
} ) + arg : : add3 ( " -unillevel " , [ ] {
arg : : shift ( ) ;
for ( auto l : all_levels ) if ( appears ( l - > name , arg : : args ( ) ) ) curlev = l ;
if ( on ) curlev - > init ( ) ;
} )
+ arg : : add3 ( " -simplemodel " , [ ] {
nisot : : geodesic_movement = false ;
pmodel = mdPerspective ;
pconf . rotational_nil = 0 ;
} ) ;
2023-08-06 20:17:20 +00:00
auto hook0 = addHook ( hooks_configfile , 300 , default_settings ) ;
2022-05-06 11:21:01 +00:00
# ifdef NILRIDER
auto hook1 =
addHook ( hooks_config , 100 , [ ] {
if ( arg : : curphase = = 1 )
conffile = " nilrider.ini " ;
if ( arg : : curphase = = 2 ) initialize_all ( ) ;
} ) ;
# endif
2022-04-24 17:48:45 +00:00
}