}
}
}
+
+void ent_route_leaderboard_ui( ui_context *ctx, ui_rect ref_box, u32 route_index )
+{
+ if( _ent_route.viewing_route_id != route_index )
+ {
+ _ent_route.viewing_route_id = route_index;
+ _ent_route.cursor[0] = 0;
+ _ent_route.cursor[1] = 0;
+ }
+
+ ui_rect leaderboard_box = { ref_box[0], ref_box[1] + ref_box[3] + 16, ref_box[2], 24 };
+
+ if( !network_connected() )
+ {
+ ui_fill( ctx, leaderboard_box, ui_opacity( GUI_COL_DARK, 0.36f ) );
+ ui_text( ctx, leaderboard_box, "Offline - No Leaderboards", 1, k_ui_align_middle_center, 0 );
+ return;
+ }
+
+ world_instance *world = &_world.main;
+ if( route_index >= af_arrcount( &world->ent_route ) )
+ {
+ ui_fill( ctx, leaderboard_box, ui_opacity( GUI_COL_DARK, 0.36f ) );
+ ui_text( ctx, leaderboard_box, "Error - Out of range", 1, k_ui_align_middle_center, 0 );
+ return;
+ }
+
+ struct leaderboard_cache *board = &world->leaderboard_cache[ route_index ];
+
+ if( board->status == k_request_status_not_found )
+ {
+ ui_fill( ctx, leaderboard_box, ui_opacity( GUI_COL_DARK, 0.36f ) );
+ ui_text( ctx, leaderboard_box, "Leaderboard not found", 1, k_ui_align_middle_center, 0 );
+ return;
+ }
+
+ if( board->status != k_request_status_ok )
+ {
+ ui_fill( ctx, leaderboard_box, ui_opacity( GUI_COL_DARK, 0.36f ) );
+ ui_text( ctx, leaderboard_box, "Leaderboard error", 1, k_ui_align_middle_center, 0 );
+ return;
+ }
+
+ vg_msg body;
+ vg_msg_init( &body, board->data, board->data_len );
+
+ if( !vg_msg_seekframe( &body, "rows" ) )
+ {
+ ui_fill( ctx, leaderboard_box, ui_opacity( GUI_COL_DARK, 0.36f ) );
+ ui_text( ctx, leaderboard_box, "No Records", 1, k_ui_align_middle_center, 0 );
+ return;
+ }
+
+ ui_fill( ctx, leaderboard_box, ui_opacity( GUI_COL_DARK, 0.36f ) );
+ ui_text( ctx, leaderboard_box, "Online Leaderboard", 1, k_ui_align_middle_center, 0 );
+ leaderboard_box[1] += leaderboard_box[3]+4;
+
+ int ml = button_press( k_srbind_mleft ),
+ mr = button_press( k_srbind_mright ),
+ mu = button_press( k_srbind_mup ),
+ md = button_press( k_srbind_mdown ),
+ mh = ml-mr,
+ mv = mu-md;
+
+ if( vg_input.display_input_method == k_input_method_controller )
+ {
+ menu_nav( &_ent_route.cursor[1], mv, _ent_route.entries_max-1 );
+ menu_nav( &_ent_route.cursor[0], mh, 1 );
+ }
+
+ i32 count = 0;
+ while( vg_msg_seekframe( &body, NULL ) )
+ {
+ ui_rect bl, br, brr;
+ ui_split( leaderboard_box, k_ui_axis_v, 48, 4, bl, br );
+ ui_split( br, k_ui_axis_v, -150, 4, br, brr );
+ leaderboard_box[1] += leaderboard_box[3]+4;
+
+ ui_fill( ctx, bl, ui_opacity( GUI_COL_DARK, 0.36f ) );
+ ui_fill( ctx, br, ui_opacity( GUI_COL_DARK, 0.36f ) );
+ ui_fill( ctx, brr, ui_opacity( GUI_COL_DARK, 0.36f ) );
+
+ char buf[100];
+ vg_str str;
+ vg_strnull( &str, buf, 100 );
+ vg_strcat( &str, "#" );
+ vg_strcati32( &str, count+1 );
+ ui_text( ctx, bl, buf, 1, k_ui_align_middle_center, 0 );
+
+ /* name */
+ const char *username = vg_msg_getkvstr( &body, "username" );
+ if( !username )
+ username = "????";
+ ui_text( ctx, br, username, 1, k_ui_align_middle_left, 0 );
+
+ /* time */
+ vg_strnull( &str, buf, 100 );
+ u32 centiseconds;
+ vg_msg_getkvintg( &body, "time", k_vg_msg_u32, ¢iseconds, NULL );
+
+ i32 seconds = centiseconds / 100,
+ minutes = seconds / 60;
+
+ centiseconds %= 100;
+ seconds %= 60;
+ minutes %= 60;
+ if( minutes > 9 ) vg_strcat( &str, "?" );
+ else vg_strcati32( &str, minutes );
+ vg_strcat( &str, ":" );
+ vg_strcati32r( &str, seconds, 2, '0' );
+ vg_strcat( &str, "." );
+ vg_strcati32r( &str, centiseconds, 2, '0' );
+ ui_text( ctx, brr, buf, 1, k_ui_align_middle_center, 0 );
+
+ if( vg_input.display_input_method == k_input_method_controller )
+ {
+ if( _ent_route.cursor[1] == count )
+ {
+ if( _ent_route.cursor[0] == 0 )
+ ui_outline( ctx, br, -1, ui_colour(ctx,k_ui_fg), 0 );
+ else if( _ent_route.cursor[0] == 1 )
+ ui_outline( ctx, brr, -1, ui_colour(ctx,k_ui_fg), 0 );
+ }
+ }
+ else
+ {
+ enum ui_button_state state = ui_button_base( ctx, br );
+ if( state == k_ui_button_hover )
+ ui_outline( ctx, br, -1, ui_colour(ctx,k_ui_fg), 0 );
+ if( state == k_ui_button_click )
+ {
+ }
+
+ state = ui_button_base( ctx, brr );
+ if( state == k_ui_button_hover )
+ ui_outline( ctx, brr, -1, ui_colour(ctx,k_ui_fg), 0 );
+ if( state == k_ui_button_click )
+ {
+ }
+ }
+
+ count ++;
+ vg_msg_skip_frame( &body );
+ }
+ _ent_route.entries_max = count;
+}
respawn_world_to_plane_pos( localplayer.rb.co, world_map.plane_pos );
world_map.boom_dist = 400.0f;
world_map.view_ready = 1;
- world_map.sel_spawn = NULL;
- world_map.close_spawn = NULL;
+ world_map.selected_entity_id = 0;
+ world_map.closest_entity_id = 0;
world_map.smooth_warm = 0;
}
world_map.final_cam.farz = 5000.0f;
world_map.final_cam.nearz = 10.0f;
- if( world_map.sel_spawn && (world_map.spawn_timer > 0.0f) )
+ if( world_map_get_transition_cam(NULL) )
{
f32 t = vg_smoothstepf( world_map.spawn_timer );
vg_camera_lerp( &localplayer.cam, &world_map.smoothed_cam, t, &world_map.final_cam );
vg_camera_finalize( &world_map.final_cam );
}
+static bool _map_closer( v3f co, f32 *closest2, f32 *d2 )
+{
+ v4f v;
+ v3_copy( co, v );
+ v[3] = 1.0f;
+ m4x4_mulv( world_map.final_cam.mtx.pv, v, v );
+ v2_divs( v, v[3], v );
+
+ *d2 = v2_dist2(v, world_map.view_centroid);
+ if( *d2 < *closest2 )
+ {
+ *closest2 = *d2;
+ return 1;
+ }
+
+ return 0;
+}
+
void render_world_map(void)
{
glEnable( GL_DEPTH_TEST );
world_map_update_final_camera( &cam );
- /* update closest spawn based on camera
+ /* update closest entity based on camera
* ------------------------------------------------------------------------------------------- */
- f32 closest2 = INFINITY;
+ f32 closest2 = INFINITY, d2;
+
for( u32 i=0; i<af_arrcount(&world->ent_spawn); i++ )
{
ent_spawn *spawn = af_arritm(&world->ent_spawn,i);
-
if( spawn->flags & k_ent_spawn_flag_locked )
continue;
- if( world_map.sel_spawn )
+ u32 spawn_ent_id = mdl_entity_id( k_ent_spawn, i );
+ if( world_map.selected_entity_id )
{
- spawn->transform.s[0] = ( spawn == world_map.sel_spawn )? 0.0f: 10000.0f;
+ spawn->transform.s[0] = ( spawn_ent_id == world_map.selected_entity_id )? 0.0f: 10000.0f;
}
else
{
- v4f v;
- v3_copy( spawn->transform.co, v );
- v[3] = 1.0f;
- m4x4_mulv( world_map.final_cam.mtx.pv, v, v );
- v2_divs( v, v[3], v );
-
- f32 d2 = v2_dist2(v, world_map.view_centroid);
- if( d2 < closest2 )
- {
- world_map.close_spawn = spawn;
- closest2 = d2;
- }
+ if( _map_closer( spawn->transform.co, &closest2, &d2 ) )
+ world_map.closest_entity_id = spawn_ent_id;
spawn->transform.s[0] = d2;
}
}
+ for( u32 i=0; i<af_arrcount(&world->ent_challenge); i++ )
+ {
+ ent_challenge *challenge = af_arritm( &world->ent_challenge, i );
+ if( challenge->flags & k_ent_challenge_locked )
+ continue;
+ u32 challenge_ent_id = mdl_entity_id( k_ent_challenge, i );
+ if( _map_closer( challenge->transform.co, &closest2, &d2 ) )
+ world_map.closest_entity_id = challenge_ent_id;
+ }
+ for( u32 i=0; i<af_arrcount(&world->ent_route); i++ )
+ {
+ ent_route *route = af_arritm( &world->ent_route, i );
+ u32 route_ent_id = mdl_entity_id( k_ent_route, i );
+ if( _map_closer( route->board_transform[3], &closest2, &d2 ) )
+ world_map.closest_entity_id = route_ent_id;
+ }
/* Do the rendering of the world in override shader
* ------------------------------------------------------------------------------------------------- */
world_prerender( world );
-
glDrawBuffers( 1, (GLenum[]){ GL_COLOR_ATTACHMENT0 } );
v3f bg;
v3_muls( world->ub_lighting.g_daysky_colour,
- world->ub_lighting.g_day_phase -
- world->ub_lighting.g_sunset_phase*0.1f, bg );
+ world->ub_lighting.g_day_phase - world->ub_lighting.g_sunset_phase*0.1f, bg );
- v3_muladds( bg, world->ub_lighting.g_sunset_colour,
- (1.0f-0.5f)*world->ub_lighting.g_sunset_phase, bg );
-
- v3_muladds( bg, world->ub_lighting.g_nightsky_colour,
- (1.0f-world->ub_lighting.g_day_phase), bg );
+ v3_muladds( bg, world->ub_lighting.g_sunset_colour, (1.0f-0.5f)*world->ub_lighting.g_sunset_phase, bg );
+ v3_muladds( bg, world->ub_lighting.g_nightsky_colour, (1.0f-world->ub_lighting.g_day_phase), bg );
glClearColor( bg[0], bg[1], bg[2], 0.0f );
glClear( GL_COLOR_BUFFER_BIT );
m4x3f identity;
m4x3_identity( identity );
- render_world_override( world, world, identity, &world_map.final_cam,
- world_map.sel_spawn? world_map.sel_spawn: world_map.close_spawn,
+
+ u32 selected_type = mdl_entity_id_type( world_map.selected_entity_id ),
+ selected_index = mdl_entity_id_id( world_map.selected_entity_id ),
+ close_type = mdl_entity_id_type( world_map.closest_entity_id ),
+ close_index = mdl_entity_id_id( world_map.closest_entity_id );
+
+ ent_spawn *dest_spawn = NULL;
+
+ if( (selected_type == k_ent_none) && (close_type == k_ent_spawn) )
+ dest_spawn = af_arritm( &world->ent_spawn, close_index );
+
+ if( selected_type == k_ent_spawn )
+ dest_spawn = af_arritm( &world->ent_spawn, selected_index );
+
+ render_world_override( world, world, identity, &world_map.final_cam, dest_spawn,
(v4f){world->tar_min, world->tar_max, 1.0f, 0.0f});
render_world_routes( world, world, identity, &world_map.final_cam, 0, 1 );
enum gui_icon icon = k_gui_icon_exclaim_2d;
if( challenge->status )
icon = k_gui_icon_tick_2d;
- respawn_map_draw_icon( &world_map.final_cam, icon, challenge->transform.co, 1.0f );
+
+ u32 challenge_id = mdl_entity_id( k_ent_challenge, i );
+ respawn_map_draw_icon( &world_map.final_cam, icon, challenge->transform.co,
+ world_map.closest_entity_id == challenge_id? 1.5f: 1.0f );
}
for( u32 i=0; i<af_arrcount(&world->ent_marker); i ++ )
if( spawn->transform.s[0] > 0.3f )
continue;
+ u32 spawn_ent_id = mdl_entity_id( k_ent_spawn, i );
f32 s = 1.0f-(spawn->transform.s[0] / 0.3f);
respawn_map_draw_icon( &world_map.final_cam,
- spawn==world_map.sel_spawn? k_gui_icon_spawn_select: k_gui_icon_spawn,
+ world_map.selected_entity_id == spawn_ent_id? k_gui_icon_spawn_select: k_gui_icon_spawn,
spawn->transform.co, s );
}
v4_copy( route->colour, colour );
v3_muls( colour, 1.6666f, colour );
gui_icon_setcolour( colour );
- respawn_map_draw_icon( &world_map.final_cam, k_gui_icon_rift_run_2d, route->board_transform[3], 1 );
+
+ u32 route_id = mdl_entity_id( k_ent_route, i );
+ respawn_map_draw_icon( &world_map.final_cam, k_gui_icon_rift_run_2d, route->board_transform[3],
+ world_map.closest_entity_id == route_id? 1.5f: 1.0f );
}
for( u32 i=0; i<af_arrcount(&world->ent_glider); i ++ )
}
}
+bool world_map_get_transition_cam( vg_camera *cam )
+{
+ u32 selected_type = mdl_entity_id_type( world_map.selected_entity_id ),
+ selected_index = mdl_entity_id_id( world_map.selected_entity_id );
+
+ if( (selected_type == k_ent_spawn) && (world_map.spawn_timer > 0.0f) )
+ {
+ if( cam )
+ vg_camera_copy( &world_map.final_cam, cam );
+
+ return 1;
+ }
+
+ return 0;
+}
+
void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *allow_back_to_exit )
{
ui_rect title_box = { main_area[2]/2 - 300/2, main_area[1] + 8, 300, 100 };
world_map.boom_dist = 400.0f;
- if( world_map.sel_spawn )
+ if( world_map.selected_entity_id )
{
+ u32 selected_type = mdl_entity_id_type( world_map.selected_entity_id ),
+ selected_index = mdl_entity_id_id( world_map.selected_entity_id );
+
/* focus camera down onto spawn */
v2f pp;
- respawn_world_to_plane_pos( world_map.sel_spawn->transform.co, pp );
+
+ if( selected_type == k_ent_spawn )
+ {
+ ent_spawn *spawn = af_arritm( &world->ent_spawn, selected_index );
+ respawn_world_to_plane_pos( spawn->transform.co, pp );
+ }
+ else if( selected_type == k_ent_challenge )
+ {
+ ent_challenge *challenge = af_arritm( &world->ent_challenge, selected_index );
+ respawn_world_to_plane_pos( challenge->transform.co, pp );
+ }
+ else if( selected_type == k_ent_route )
+ {
+ ent_route *route = af_arritm( &world->ent_route, selected_index );
+ respawn_world_to_plane_pos( route->board_transform[3], pp );
+ }
+ else
+ v2_zero( pp );
+
v2_lerp( world_map.plane_pos, pp, vg.time_frame_delta*2.0f, world_map.plane_pos );
world_map.boom_dist = 200.0f;
{
skaterift.activity = k_skaterift_default;
srinput.state = k_input_state_resume;
- world_map.sel_spawn = NULL;
+ world_map.selected_entity_id = 0;
}
}
else
ctx->font = &vgf_default_title;
ui_rect label_box = { spawn_box[0], spawn_box[1] + 8, spawn_box[2], 48 };
- ui_text( ctx, label_box, "Spawnpoint", 1, k_ui_align_center, ui_colour(ctx,k_ui_yellow) );
+
+ const char *title_text = "Spawnpoint";
+ if( selected_type == k_ent_challenge )
+ title_text = "Challenge";
+ else if( selected_type == k_ent_route )
+ title_text = "Race";
+ ui_text( ctx, label_box, title_text, 1, k_ui_align_center, ui_colour(ctx,k_ui_yellow) );
bool spawn_here = 0,
- exit_spawn = 0;
+ exit_this = 0;
ui_rect no_box = { spawn_box[0] + spawn_box[2]-32, spawn_box[1], 32, 32 };
if( menu_button_rect( ctx, no_box, 0, 1, "X" ) )
{
- exit_spawn = 1;
+ exit_this = 1;
}
ctx->font = &vgf_default_large;
- ui_rect yes_box = { spawn_box[0]+(spawn_box[2]-100)/2, spawn_box[1]+spawn_box[3]-32, 100, 32 };
- if( menu_button_rect( ctx, yes_box, vg_input.display_input_method == k_input_method_controller, 1, "Spawn" ) )
+
+ if( selected_type == k_ent_spawn )
{
- spawn_here = 1;
+ ui_rect yes_box = { spawn_box[0]+(spawn_box[2]-100)/2, spawn_box[1]+spawn_box[3]-32, 100, 32 };
+ if( menu_button_rect( ctx, yes_box, vg_input.display_input_method == k_input_method_controller, 1, "Spawn" ) )
+ spawn_here = 1;
+
+ if( button_down( k_srbind_maccept ) )
+ spawn_here = 1;
+ }
+ else
+ {
+ ui_rect name_box = { spawn_box[0], label_box[1] + label_box[3],
+ spawn_box[2], (spawn_box[1] + spawn_box[3]) - (label_box[1] + label_box[3]) };
+
+ const char *name = "???";
+ if( selected_type == k_ent_challenge )
+ {
+ ent_challenge *challenge = af_arritm( &world->ent_challenge, selected_index );
+ name = af_str( &world->meta.af, challenge->pstr_alias );
+ }
+ else if( selected_type == k_ent_route )
+ {
+ ent_route *route = af_arritm( &world->ent_route, selected_index );
+ name = af_str( &world->meta.af, route->pstr_name );
+ ent_route_leaderboard_ui( ctx, spawn_box, selected_index );
+ }
+ ui_text( ctx, name_box, name, 1, k_ui_align_middle_center, 0 );
}
- if( button_down( k_srbind_maccept ) )
- spawn_here = 1;
if( button_down( k_srbind_mback ) )
- exit_spawn = 1;
+ exit_this = 1;
if( spawn_here )
{
- player__spawn( world_map.sel_spawn );
+ player__spawn( af_arritm( &world->ent_spawn, selected_index ) );
world_map.spawn_timer = 1.0f;
}
- else if( exit_spawn )
+ else if( exit_this )
{
- world_map.sel_spawn = NULL;
+ world_map.selected_entity_id = 0;
}
}
}
if( (world->meta.version >= 109) && af_arrcount( &world->ent_region ) )
{
ui_rect stat_panel = { main_area[0]+main_area[2]-(256+8), main_area[1]+8, 256, main_area[3]-16 };
+ main_area[2] = stat_panel[0] - main_area[0]; // for mouse clipping
+
u32 c0 = ui_opacity( GUI_COL_DARK, 0.36f );
ui_fill( ctx, stat_panel, c0 );
-
ui_rect_pad( stat_panel, (ui_px[2]){8,0} );
for( u32 i=0; i<af_arrcount( &world->ent_region ); i ++ )
u32 type = mdl_entity_id_type( ref->entity_id ),
index = mdl_entity_id_id( ref->entity_id );
+ if( !((type == k_ent_route) || (type == k_ent_challenge)) )
+ continue;
+
+ ui_rect r;
+ ui_standard_widget( ctx, stat_panel, r, 1 );
+
+ ui_rect b;
+ rect_copy( r, b );
+ b[0] -= 16;
+ b[2] += 16;
+
+ if( ref->entity_id == world_map.selected_entity_id )
+ {
+ ui_outline( ctx, b, -1, ui_colour(ctx,k_ui_blue), 0 );
+ }
+ else
+ {
+ enum ui_button_state state = ui_button_base( ctx, b );
+ if( state == k_ui_button_hover )
+ ui_outline( ctx, b, -2, ui_colour(ctx,k_ui_fg), 0 );
+
+ if( state == k_ui_button_click )
+ {
+ world_map.selected_entity_id = ref->entity_id;
+ }
+ }
+
if( type == k_ent_route )
{
ent_route *route = af_arritm( &world->ent_route, index );
vg_strcat( &str, " \xb3");
if( route->flags & k_ent_route_flag_achieve_gold )
vg_strcat( &str, "\xb3");
-
- ui_rect r;
- ui_standard_widget( ctx, stat_panel, r, 1 );
ui_text( ctx, r, buf, 1, k_ui_align_middle_left, medal_colour( ctx, route->flags ) );
}
else if( type == k_ent_challenge )
}
combined &= flags;
-
- ui_rect r;
- ui_standard_widget( ctx, stat_panel, r, 1 );
ui_text( ctx, r, buf, 1, k_ui_align_middle_left, medal_colour( ctx, flags ) );
}
}
if( ctx->focused_control_type == k_ui_control_none )
{
- if( world_map.close_spawn )
+ if( world_map.closest_entity_id )
{
if( vg_input.display_input_method == k_input_method_kbm )
{
{
if( ui_click_up(ctx, UI_MOUSE_LEFT) )
{
- world_map.sel_spawn = world_map.close_spawn;
+ world_map.selected_entity_id = world_map.closest_entity_id;
}
}
}
else
{
if( button_down( k_srbind_maccept ) )
- world_map.sel_spawn = world_map.close_spawn;
+ world_map.selected_entity_id = world_map.closest_entity_id;
}
}
}
i32 R = menu_nav( selected_world_index, mv, menu.world_list_total_count-1 );
-
if( menu_button( ctx, panel, R == -999, page>0, "\x94" ) )
{
*selected_world_index = (page-1)*menu.world_list_nominal_display_count;